基于ListItem特定variables在ListItem上膨胀布局

我正在使用SimpleCursorAdapterListView来显示一些使用Loader加载的数据。 在cursor内部,我有一个int从0到3的项目。

我想这个int等于0-1的项目有一个布局(右alignment,一种颜色)和2-3项目有另一个布局(左alignment,另一种颜色)。 much like a chat app, where sent messages are on the right and received ones are on the left.

有一个简单的方法来做到这一点? 像一个开关,其中0-1充气layout_1和2-3我膨胀layout_2。

编辑:我已经添加了我试图填充ListFragment的代码。 用作开关的int是MyContentProvider.Data.E_TYPE。 我无法得到它的窍门,但也许有人可以清楚地解释我要写的东西!

  import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuInflater; import com.corsalini.survcontr.MyContentProvider.Data; import android.content.ContentResolver; import android.content.ContentValues; import android.database.Cursor; import android.os.Bundle; import android.support.v4.app.ListFragment; import android.support.v4.content.CursorLoader; import android.support.v4.app.LoaderManager; import android.support.v4.content.Loader; import android.support.v4.widget.CursorAdapter; import android.support.v4.widget.SimpleCursorAdapter; import android.util.Log; import android.view.View; import android.widget.ListView; public class FragEvents extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor>{ @Override public void onPause() { allRead(); super.onPause(); } private static final int EVENTS_LOADER = 0x02; // This is the Adapter being used to display the list's data. SimpleCursorAdapter mAdapter; // If non-null, this is the current filter the user has provided. String mCurFilter; @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // Give some text to display if there is no data. In a real // application this would come from a resource. setEmptyText(this.getString(R.string.perform_event)); // We have a menu item to show in action bar. setHasOptionsMenu(true); // Create an empty adapter we will use to display the loaded data. mAdapter = new SimpleCursorAdapter(getActivity(), android.R.layout.simple_list_item_2, null, new String[] { MyContentProvider.Data.E_TEXT, MyContentProvider.Data.E_DATE, MyContentProvider.Data.E_NUMBER, MyContentProvider.Data.E_TYPE }, new int[] { android.R.id.text1, android.R.id.text2 }, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER); setListAdapter(mAdapter); // Start out with a progress indicator. setListShown(false); // Prepare the loader. Either re-connect with an existing one, // or start a new one. getActivity().getSupportLoaderManager().initLoader(EVENTS_LOADER, null, this); } public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.menu_events, menu); } @Override public void onListItemClick(ListView l, View v, int position, long id) { //TODO Insert desired behavior here. Log.i("FragmentComplexList", "Item clicked: " + id); } // These are the Contacts rows that we will retrieve. static final String[] SUMMARY_PROJECTION = new String[] { MyContentProvider.Data.E_ID, MyContentProvider.Data.E_DATE, MyContentProvider.Data.E_NUMBER, MyContentProvider.Data.E_TEXT, MyContentProvider.Data.E_TYPE, }; public Loader<Cursor> onCreateLoader(int id, Bundle args) { return new CursorLoader(getActivity(), MyContentProvider.Data.CONTENT_URI_EVENTS, SUMMARY_PROJECTION, null, null, Data.E_ID + " DESC"); } public void onLoadFinished(Loader<Cursor> loader, Cursor data) { // Swap the new cursor in. (The framework will take care of closing the // old cursor once we return.) mAdapter.swapCursor(data); // The list should now be shown. if (isResumed()) { setListShown(true); } else { setListShownNoAnimation(true); } } public void onLoaderReset(Loader<Cursor> loader) { // This is called when the last Cursor provided to onLoadFinished() // above is about to be closed. We need to make sure we are no // longer using it. mAdapter.swapCursor(null); } public void deleteEvent(ContentResolver contentResolver, long id){ String selection = Data.E_ID + "="; String[] args = {String.valueOf(id)}; contentResolver.delete(Data.CONTENT_URI_EVENTS, selection, args); } public void allRead(){ ContentResolver contentResolver = getActivity().getContentResolver(); ContentValues contentValue = new ContentValues(); contentValue.put(Data.E_NUMBER, Data.RECEIVED_READ); String selection= Data.E_TYPE+"="; String[] args= {String.valueOf(Data.RECEIVED_UNREAD)}; contentResolver.update(Data.CONTENT_URI_EVENTS, contentValue, selection, args); } } 

编辑:如果我得到它的权利,我最后的EventsAdapter(它扩展了SimpleCursorAdapter)应该看起来像这样:

  import android.content.Context; import android.database.Cursor; import android.support.v4.widget.SimpleCursorAdapter; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class EventsAdapter extends SimpleCursorAdapter { private Context localContext; public EventsAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags) { super(context, layout, c, from, to, flags); localContext = context; } @Override public View getView(int position, View convertView, ViewGroup parent) { Cursor c= getCursor(); c.moveToPosition(position); if(convertView == null) { LayoutInflater layoutInflator = (LayoutInflater)localContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); switch (getItemViewType(position)){ case 0: convertView = layoutInflator.inflate(R.layout.item_event_0, null); break; case 1: convertView = layoutInflator.inflate(R.layout.item_event_1, null); break; case 2: convertView = layoutInflator.inflate(R.layout.item_event_2, null); break; case 3: convertView = layoutInflator.inflate(R.layout.item_event_3, null); break; } } switch (getItemViewType(position)){ case 0: TextView date0=(TextView)convertView.findViewById(R.id.date0); TextView text0=(TextView)convertView.findViewById(R.id.text0); date0.setText(""+c.getString(c.getColumnIndex(Data.E_DATE))); text0.setText(""+c.getString(c.getColumnIndex(Data.E_TEXT))); break; case 1: TextView date1=(TextView)convertView.findViewById(R.id.date1); TextView text1=(TextView)convertView.findViewById(R.id.text1); date1.setText(""+c.getString(c.getColumnIndex(Data.E_DATE))); text1.setText(""+c.getString(c.getColumnIndex(Data.E_TEXT))); case 2: TextView date2=(TextView)convertView.findViewById(R.id.date2); TextView text2=(TextView)convertView.findViewById(R.id.text2); date2.setText(""+c.getString(c.getColumnIndex(Data.E_DATE))); text2.setText(""+c.getString(c.getColumnIndex(Data.E_TEXT))); case 3: TextView date3=(TextView)convertView.findViewById(R.id.date3); TextView text3=(TextView)convertView.findViewById(R.id.text3); date3.setText(""+c.getString(c.getColumnIndex(Data.E_DATE))); text3.setText(""+c.getString(c.getColumnIndex(Data.E_TEXT))); } return convertView; } @Override public int getItemViewType(int position) { int type = 0; int returnInt = 0; Cursor c= getCursor(); c.moveToPosition(position); type= c.getInt(c.getColumnIndex(Data.E_TYPE)); switch (type){ case Data.RECEIVED_READ: returnInt=3; case Data.RECEIVED_UNREAD: returnInt= 2; case Data.SENT_COMPLETED: returnInt= 1; case Data.SENT_PROGRESS: returnInt= 0; default: returnInt=0; } return returnInt; } @Override public int getViewTypeCount() { return 4; } } 

Solutions Collecting From Web of "基于ListItem特定variables在ListItem上膨胀布局"

使用ListViews(尤其是像你所描述的那样复杂的)来处理视图回收是非常重要的。 BaseAdapter类是SimpleCursorAdapter的超类,有几个方法可以在使用最less的资源时重写以达到所需的效果。 我以前从来没有使用过SimpleCursorAdatper,所以这是用普通的CursorAdapter来编写的,但是你可以用任何覆盖BaseAdapter的Adapter类来使用它。

Android中的ListViews以非常特定的方式来降低内存成本。 当您滚动浏览ListView时,移出屏幕的项目的视图被放置在一个小的视图池中。 convertView参数是从这个池中获取的。 他们这样做是因为将每个列表项视图保存在内存中并不能很好地扩展,并可能很快导致OutOfMemoryexception。 getView()方法是将这些视图和configuration为当前列表项的位置。 通常你会看到如下所示的行:

 if(convertView == null) convertView = layoutInflator.inflate(R.layout.list_item, null); 

在这种情况下,如果convertView不为null,我们知道它以前是膨胀的。 我们不想重新膨胀它,因为这是一个代价高昂的操作,getView应该在数据显示之前快速填充数据视图。

现在,在你的情况下,convertView有两种潜在的通货膨胀。 我们可以重写基类中的两个方法,以确保convertView始终是正确的,而不是每次重新使用视图(非常糟糕)或者使用某种独特的资源ID的hack(更好,但并不理想)types。 这两个方法是getItemViewCount()getItemViewType(int position)

适配器使用getItemViewCount()来确定应为列表维护多less个视图池。 重写它很简单,在你的情况下,会看起来像这样。

 @Override public int getViewTypeCount() { return 2; //Even though you have four cases, there are only 2 view types. } 

getItemViewType(int position)由Adapter使用getView被调用来决定哪个pool应该来自哪个池。 在这里,你需要一个开关或if / else语句来检查你的底层数据源是哪个视图types并返回它。 (注意,根据Android文档,这里的返回值必须介于0和getViewTypeCount()-1之间,所以在你的情况下是0或1)

 @Override public int getItemViewType(int position) { Item item = getItem(position) //Or however you're getting the data associated with a particular list position switch(item.myInt) { //I simplified this a bit, basically, check your int, if it's the first type, return 0 for your first layout type, else return 1 for your second. case(0): case(1): return 0; case(2): case(3): return 1; } } 

现在,最后,我们将修改getView来执行初始layoutInflation,以便在池中拥有正确的Views。

 @Override public View getView(int position, View convertView, ViewGroup viewParent) { //if convertView is not null, we got a view from the pool, just go on if(convertView == null) { //This means we didn't have a view in the pool to match this view type. Inflate it and it will be placed in the proper pool when this list item is scrolled off the screen if(getItemViewType(position) == 0) convertView = layoutInflator.inflate(R.layout.list_item_type1, null); else if(getItemViewType(position) == 1) convertView = layoutInflator.inflate(R.layout.list_item_type2, null); } //Populate the view with whatever data you need here //And finally.... return convertView; } 

ListViews及其适配器是我在Android中遇到的最复杂的事情之一,但花时间做正确的操作将大大提高应用程序的性能和用户体验。 祝你好运!

我觉得你只需要在你的getView(int position, View convertView, ViewGroup parent)方法上膨胀正确的布局:

 MyItem item = getItem(position); View vi = convertView; if(vi == null){ switch(item.getStatus()) { case 0: vi = mInflater.inflate(R.layout.item1, null); break; case 1: vi = mInflater.inflate(R.layout.item2, null); break; case 2: vi = mInflater.inflate(R.layout.item3, null); break; } //set viewholder ... }else{ //get viewholder ... } // set values to views ... 

这是你需要的吗?