第六章 使用列表(list)和适配器(adapter)

来源:互联网 发布:最新淘宝打包员招聘 编辑:程序博客网 时间:2024/06/03 23:50

列表和适配器是安卓开发中需要重点掌握的两个概念,在这章中,我们将学习列表和适配器的一些技巧。


1.处理空列表

当列表中没有内容的时候,可以展示一张图片或者文字进行提示,只需要使用ListView的setEmpltyView(view)方法即可。当adapter为null或者adapter的 isEmpty()方法返回true的时候就会展示出来。
例如:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="vertical" >    <ListView        android:id="@+id/my_list_view"        android:layout_width="fill_parent"        android:layout_height="fill_parent" />    <ImageView        android:id="@+id/empty_view"        android:layout_width="fill_parent"        android:layout_height="fill_parent"        android:src="@drawable/empty_view" /></FrameLayout>
当ListView为空时我们想展示ImageView这张图片,那么在java代码里可以这样写:
  public void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.main);    mListView = (ListView) findViewById(R.id.my_list_view);    mListView.setEmptyView(findViewById(R.id.empty_view));  }

2.使用ViewHolder创建高效适配器

地球人都知道怎么用,这里就不重复了。


3.给ListView添加section headers

效果如图:

具体实现步骤如下:
首先,section header布局:把背景设置为蓝色,与listview的item区分开来
<TextView xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/header"    android:textSize="24sp"    android:layout_width="fill_parent"    android:layout_height="wrap_content"    android:background="#0000ff" />
然后,页面布局:通过include把header添加进来,这样section header会保持在listview顶部
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="@android:color/white">    <ListView        android:id="@+id/my_list"        android:layout_width="match_parent"        android:layout_height="match_parent" />    <include layout="@layout/header" /></FrameLayout>
再是listview的item布局:每一个item都包含一个header,需要时显示,不需要时隐藏
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:orientation="vertical" >    <include layout="@layout/header" />    <TextView        android:id="@+id/label"        style="@android:style/TextAppearance.Large"        android:layout_width="match_parent"        android:layout_height="wrap_content" /></LinearLayout>
adapter的getview方法中:当item在顶部,或者item的首字母与前一个item的首字母不一样时,就显示section header
  public View getView(int position, View view, ViewGroup parent) {    final  ViewHolder viewHolder;    if (view == null) {      view = activity.getLayoutInflater().inflate(R.layout.list_item, parent, false);      viewHolder=new ViewHolder();      viewHolder.header=(TextView) view.findViewById(R.id.header);      viewHolder.label=(TextView)view.findViewById(R.id.label);      view.setTag(viewHolder);    }else {      viewHolder=(ViewHolder)view.getTag();    }    //赋值    String label = countries[position];    if (position == 0 || countries[position - 1].charAt(0) != label.charAt(0)) {      viewHolder.header.setVisibility(View.VISIBLE);      viewHolder.header.setText(label.substring(0, 1));    } else {      viewHolder.header.setVisibility(View.GONE);    }    viewHolder.label.setText(countries[position]);    return view;  }  static class ViewHolder{    TextView header;    TextView label;  }
然后在activity中:初始化ListView,并添加滑动监听,使得处于listview顶部的section header的标签与item的首字母相同。
public class MainActivity extends Activity {  private TextView topHeader;  private int topVisiblePosition = -1;  private ListView mList;  @Override  public void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.list);    topHeader = (TextView) findViewById(R.id.header);    mList=(ListView)findViewById(R.id.my_list);    mList.setAdapter(new SectionAdapter(this, Countries.COUNTRIES));    mList.setOnScrollListener(        new AbsListView.OnScrollListener() {          @Override          public void onScrollStateChanged(AbsListView view,              int scrollState) {            // Empty.          }          @Override          public void onScroll(AbsListView view, int firstVisibleItem,              int visibleItemCount, int totalItemCount) {            if (firstVisibleItem != topVisiblePosition) {              topVisiblePosition = firstVisibleItem;              setTopHeader(firstVisibleItem);            }          }        });    setTopHeader(0);  }  private void setTopHeader(int pos) {    final String text = Countries.COUNTRIES[pos].substring(0, 1);    topHeader.setText(text);  }}

4.使用委托delegate让Activity和Adapter通信

比如一个ListView中有一个按钮,点击按钮能删除当前item。如果Activity和Adapter写在两个不同的java文件中,那么在adapter中需要能修改ListView中的数据,就可以使用委托来实现。
adapter代码如下:
public class NumbersAdapter extends ArrayAdapter<Integer> {  public static interface NumbersAdapterDelegate {    void removeItem(Integer value);  }  private LayoutInflater mInflator;  private NumbersAdapterDelegate mDelegate;  public NumbersAdapter(Context context, List<Integer> objects) {    super(context, 0, objects);    mInflator = LayoutInflater.from(context);  }  @Override  public View getView(int position, View cv, ViewGroup parent) {    if (null == cv) {      cv = mInflator.inflate(R.layout.number_row, parent, false);    }    final Integer value = getItem(position);    TextView tv = (TextView) cv.findViewById(R.id.numbers_row_text);    tv.setText(value.toString());    View button = cv.findViewById(R.id.numbers_row_button);    button.setOnClickListener(new OnClickListener() {      @Override      public void onClick(View v) {        if (null != mDelegate) {          mDelegate.removeItem(value);        }      }    });    return cv;  }  public void setDelegate(NumbersAdapterDelegate delegate) {    mDelegate = delegate;  }}
其实就是在adapter中定义了一个接口,然后在item的按钮点击事件中调用接口中的方法。
Activity代码如下:让activity继承adapter中的接口,然后实现接口中的方法。当用户点击item中的按钮,就会调用activity中的removeItem方法
public class MainActivity extends Activity implements NumbersAdapterDelegate {  private ListView mListView;  private ArrayList<Integer> mNumbers;  private NumbersAdapter mAdapter;  private EditText mEditText;  @Override  public void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.main);    mEditText = (EditText) findViewById(R.id.main_edittext);    mListView = (ListView) findViewById(R.id.main_listview);    mNumbers = new ArrayList<Integer>();    mAdapter = new NumbersAdapter(this, mNumbers);    mListView.setAdapter(mAdapter);  }  @Override  protected void onResume() {    super.onResume();    mAdapter.setDelegate(this);  }  @Override  protected void onPause() {    super.onPause();    mAdapter.setDelegate(null);  }  @Override  public void removeItem(Integer value) {    mNumbers.remove(value);    Toast.makeText(this, "Removed object: " + value, Toast.LENGTH_SHORT).show();    mAdapter.notifyDataSetChanged();  }}


5.其它

1.设定屏幕的方向
其中一个方法是在manifest.xml里设定activity的属性 android:screenOrientation="landscape"
也可在Activity的Java文件中通过代码设定:setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);

setRequestedOrientation 参数说明:

  • 系统默认:此为默认值,由Android系统自己选择适当的方向,选择策略视具体设备的配置情况而定,因此不同的设备会有不同的方向选择;
    ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
  • 锁定直式:竖屏 (肖像照) , 显示时高度大于宽度 ;
    ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
  • 锁定横式:横屏(风景照) ,显示时宽度大于高度;
    ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
  • 随使用者当下:用户当前的首选方向;
    ActivityInfo.SCREEN_ORIENTATION_USER
  • 与活动线程下相同的设定:继承Activity堆栈中当前Activity下面的那个Activity的方向;
    ActivityInfo.SCREEN_ORIENTATION_BEHIND
  • 不随SENSOR改变:忽略物理感应器 即显示方向与物理感应器无关,不管用户如何旋转设备显示方向都不会随着改变("unspecified"设置除外);
    ActivityInfo.SCREEN_ORIENTATION_NOSENSOR
  • 随SENSOR改变:由物理感应器决定显示方向,它取决于用户如何持有设备,当 设备 被旋转时方向会随之变化 在横屏与竖屏之间;
    ActivityInfo.SCREEN_ORIENTATION_SENSOR
2.ListView的选择模式choiceMode

 android:choiceMode="multipleChoice"
 choiceMode属性解析
ConstantValueDescriptionnone0Normal list that does not indicate choices.singleChoice1The list allows up to one choice.multipleChoice2The list allows multiple choices.multipleChoiceModal3The list allows multiple choices in a custom selection mode.

0 0
原创粉丝点击