【转】 Pro Android学习笔记(十九):用户界面和控制(7):ListView

目录(?)[-]

  1. 点击List的item触发
  2. 添加其他控件以及获取item数据

ListView控件以垂直布局方式显示子view。系统的android.app.ListActivity已经实现了一个只含有一个ListView的Activity,并通过setListAdapter()方法来管理adapter。我们可以通过扩展ListActivity来实现。

我们要在整个屏幕上显示ListView,我们直接继承使用ListActivity,不需要在定义自己的layout XML文件,我们在上一学习中已经进行了相关小例子的演示。

点击List的item触发

我们沿用之前呈现联系人姓名的例子,在上面加上点击触发的处理。以前我们试过内部类调用和对象调用,这次也采用对象调用。

public class UiAdapterDemo extends ListActivity implements OnItemClickListener{
  
    protected void onCreate(Bundle savedInstanceState) {  
        ……  //代码见 Pro Android学习笔记(十八):用户界面和控制(6):Adapter和AdapterView 的第一个小例子         
        ListView lv = getListView();  //获取ListView控件 
        lv.setOnItemClickListener(this);  //稍微做点变化
        Log.d("UiAdapterDemo","Listview is " + lv.toString());
    }

//请配合下面运行的结果图来看各参数的含义 
    public void onItemClick(AdapterView<?> parent, View view, int position, long rowId) {
        // parent本例就是ListView,可以验证和listview是同一对象 
        Log.d("onItemClick","parent : " + parent.toString()); 
        // position是在list的位置,即子view的序号,从0还是计算。rowId是数据源的序号,与具体的数据源方式有关,如果来自cursor,这是_ID,如果来自array,则是array[rowId]。 
        Log.d("onItemClick","position = " + position + "   Row id is " + rowId);

//在层次结构上,一般是ListView –>子View(Layout)—>子View中的具体控件,而本例的结构很简单为ListView –> 子View(TextView),我们可以通过这两种方式来获取具体控件的信息
        //方式1:ListView –> 子View(TextView) view就是子view,本例是android.R.layout.simple_list_item_1,就是一个简单的TextView,所以子view就是TextView。
        Log.d("onItemClick","view : " + view.toString()); 
        Log.d("onItemClick","name : " + ((TextView)view).getText()); 
        //方式2: ListView –>子View(Layout)—>子View中的具体控件也可以按ApdaterView的结构,将子view视为是一个容器,通过findViewById找到里面相应的控件,两种方式的结果是一样。
        TextView tv = (TextView) view.findViewById(android.R.id.text1); 
        Log.d("onItemClick","tv : " + tv.toString()); 
        Log.d("onItemClick","name : " + tv.getText());

//点击触发打开该联系人,在content Provider的情况下,rowId就是_ID,但如果是ArrayAdapter,则rowId就是在数组的位置,即position和rowId会一样。
        Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, rowId);
        Intent intent = new Intent(Intent.ACTION_VIEW,uri); 
        startActivity(intent); 
    } 
}

在这个例子中,我们在联系人程序中修改联系人信息,发现ListView会自动同步,这是SimpleCursorAdapter带来的好处,然而,如果我们使用ArrayAdapter,则需要notifyDataSetChanged( )。

添加其他控件,以及获取item数据

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="vertical" > 
    <ListView android:id="@android:id/list"  <!-- ListActivity将使用该ID的listview,如果要extends ListActivity --> 
        android:layout_width="match_parent"
        android:layout_height="0dip"   
        android:layout_weight="1"
 /> <!-- 设置layout_height=0dip和layout_weight=1,目的是确保屏幕有足够的地方显示其他控件,本例是确保button出现在屏幕的下方,即时List的items数很多,需要翻屏显示,button也能一直出现在最下方 -->
      
    <Button android:id="@+id/ui_listbutton" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:text="@string/submit" 
        android:onClick="submitFunc" /> 
</LinearLayout>

相关代码和运行结果如下:

public class UiAdapterDemo2 extends ListActivity{
    private int idCol; 
    private int nameCol; 
    private int timesContacted; 
    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState);   
        setContentView(R.layout.ui_add_listview);     //使用我们自定义的layout 
        CursorLoader cursorLoader = new CursorLoader(getApplicationContext(),
                ContactsContract.Contacts.CONTENT_URI, 
                null, null, null, ContactsContract.Contacts.DISPLAY_NAME + " ASC");
        cur = cursorLoader.loadInBackground(); 
        //获取Cusor数据源中各项关键信息的列index,用于后面的信息检索 
        idCol = cur.getColumnIndex(ContactsContract.Contacts._ID); 
        nameCol = cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME); 
        timesContactedCol = cur.getColumnIndex(ContactsContract.Contacts.TIMES_CONTACTED);

String[] cols = new String[]{ContactsContract.Contacts.DISPLAY_NAME};
        int[] views = new int[]{android.R.id.text1};  
        SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
                android.R.layout.simple_list_item_multiple_choice,  //这是子View的layout,打开源代码文件,我们看到这是id为android.R.id.text1(这就是int[] views所填的值)的CheckedTextView,CheckedTextView是TextView的子类,样子是一个TextView和一个CheckBox
                cur, cols, views,CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);

this.setListAdapter(adapter);

ListView lv = getListView(); 
        lv.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);  //设置listview模式,使用多选模式。缺省是CHOICE_MODE_NONE,此外还有CHOICE_MODE_SINGLE(相应的,我们在adapter中设置sub view可以用android.R.layout.simple_list_item_single_choice。 
    } 
    
    public void submitFunc(View v){ 
        ListView lv = getListView(); 
        SparseBooleanArray positionChecked = lv.getCheckedItemPositions(); // 来自android.widget.AbsListView的函数,用于存放多选择模式listview的选择情况 
        for(int i = 0 ; i < lv.getCount() ; i ++){ 
            Log.d("listAddControl","position [" + i +"] " + positionChecked.get(i));
        } 
        
        for(int i = 0 ; i < lv.getCount(); i++){    //找出item的对应的数据源,显示更为详细的信息
            if(positionChecked.get(i)){ 
                cur.moveToPosition(i);  //在这里也可以使用AdapterView的 Object getItemAtPosition(int position),在Content Provider,中返回的是CursorWrapper,返回信息格式与具体的数据源相关。本例也可以使用CursorWrapper cw = (CursorWrapper) lv.getItemAtPosition(i);
                Log.d("listAddControl","[" + i  +"]: _id=" + cur.getLong(idCol) + "   " + cur.getString(nameCol)
                        + "   Contact times:" + cur.getInt(timesContactedCol)); 
            } 
        } 
    }

}

我们换一种方式来写summitFunc,代码如下:

public void submitFunc(View v){ 
    if(!adapter.hasStableIds()){  //询问在数据变更时,ID会不会也随之变化。true表示不变
        Log.d("listAddControl","Not the same id always refers to the same object."); 
        return;  
    }  
         
    ListView lv = getListView();  
    long[] viewItems = lv.getCheckedItemIds();  //这是本次实验的内容,本例是Content provider,则返回为_ID。在使用getCheckedItemIds(),建议先用hasStabledIds来确认获得的Id值是否稳定不变。。 
    for (int i = 0 ; i < viewItems.length ; i ++){ 
        Log.d("listAddControl", "cheked Item Id : " + viewItems[i]);  
        Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, viewItems[i]); 
        Log.d("listAddControl", uri.toString());  
    } 
}

在这个例子中,我们获得了_ID,就可以构造URI,从provider中直接读取信息,因此,我们就没有必要将联系的所有信息都放置在cursor中,不需要占那么所资源。注意,_ID是必须要读取。

String[] projects = {ContactsContract.Contacts._ID,ContactsContract.Contacts.DISPLAY_NAME}; 
CursorLoader cursorLoader = new CursorLoader(getApplicationContext(), 
                ContactsContract.Contacts.CONTENT_URI,  
                projects,  null, null, ContactsContract.Contacts.DISPLAY_NAME + " ASC");

相关链接: 我的Android开发相关文章

时间: 2024-10-25 23:31:23

【转】 Pro Android学习笔记(十九):用户界面和控制(7):ListView的相关文章

Android学习笔记十九.使用ContentProvider实现数据共享(一)

一.Android如何实现数据共享?  为了在应用程序之间交换数据,Android提供了ContentProvider,ContentProvider是不同应用程序之间进行数据交换的标准API,当一个应用程序需要把自己的数据暴露给其他程序使用时,该应用程序就可通过提供ContentProvider来实现,其他的应用程序就可以通过ContentResolver来操作ContentProvider暴露的数据.一旦某个应用程序通过ContentProvider暴露了自己的数据操作接口,那么不管该应用程

Pro Android学习笔记(二九):用户界面和控制(17):include和merge

xml控件代码重用:include 如果我们定义一个控件,需要在不同的layout中重复使用,或者在同一个layout中重复使用,可以采用include的方式.例如定义my_button.xml如下 <?xml version="1.0" encoding="utf-8"?> <Button xmlns:android="http://schemas.android.com/apk/res/android"     androi

【转】 Pro Android学习笔记(二九):用户界面和控制(17):include和merge

目录(?)[-] xml控件代码重用include xml控件代码重用merge 横屏和竖屏landsacpe portrait xml控件代码重用:include 如果我们定义一个控件,需要在不同的layout中重复使用,或者在同一个layout中重复使用,可以采用include的方式.例如定义my_button.xml如下 <?xml version="1.0" encoding="utf-8"?> <Button xmlns:android=

【转】Pro Android学习笔记(二五):用户界面和控制(13):LinearLayout和TableLayout

目录(?)[-] 布局Layout 线性布局LinearLayout 表格布局TableLayout 布局Layout Layout是容器,用于对所包含的view进行布局.layout是view的子类,所以可以作为view嵌入到其他的layout中.Android的layout有LinearLayout.TableLayout,RelativeLayout.FrameLayout.GridLayout. 线性布局:LinearLayout 这是最常用的,有anroid:orientation来确

【转】 Pro Android学习笔记(二二):用户界面和控制(10):自定义Adapter

目录(?)[-] 设计Adapter的布局 代码部分 Activity的代码 MyAdapter的代码数据源和构造函数 MyAdapter的代码实现自定义的adapter MyAdapter的代码继续探讨BaseAdapter 我们可以同继承抽象类BaseAdapter来实现自己的Adapter,自己设置子View的UI,不同子View可以由不同的布局,并自己进行数据和子view中数据的对应关系.图是例子的呈现结果,我们有很多图标,对这些图标按一定大小进行缩放,然后布局在GridView中.这个

【转】 Pro Android学习笔记(四十):Fragment(5):适应不同屏幕或排版

目录(?)[-] 设置横排和竖排的不同排版风格 改写代码 对于fragment,经常涉及不同屏幕尺寸和不同的排版风格.我们在基础小例子上做一下改动,在横排的时候,仍是现实左右两个fragment,在竖排时,如下图显示: 屏幕上只显示一个fragment,点击列表上的数目,进入到简介的activity.下面介绍实现的方式. 设置横排和竖排的不同排版风格 在 Pro Android学习笔记(四):了解Android资源(下)的“资源和配置的变更”中,我们介绍了如何同资源文件夹名设置不同资源.缺省的l

【转】 Pro Android学习笔记(五二):ActionBar(5):list模式

可以在action bar中加入spinner的下来菜单,有关spinner,可以参考Pro Android学习笔记(二十):用户界面和控制(8):GridView和Spinner. list的样式和theme有关,如果theme设置不正确,还可能会出现异常. 相关的代码如下: public class ListActionBarDemo extends SearchTestCase3 implements OnNavigationListener{ //List触发的回调函数接口    @Ov

Pro Android学习笔记(三三):Menu(4):Alternative菜单

什么是Alternative menu(替代菜单) 举个例子,Activity显示一个文本文件.如果用户想对文本文件进行编辑,Activity不提供编辑能力,但可由其他activity或者其他应用提供.我们将相关信息存储在一个intent中,例如该文本的Uri.这个intent可以匹配系统的多个应用,替代菜单将这些应用一一列出,菜单项的title就是该可被调用的activity的名字,图标也为该可被调用的activity的图表. 小例子说明 我们通过一个小例子进行学习,简单地打开一个URL:we

Pro Android学习笔记 ActionBar(1):Home图标区

 Pro Android学习笔记(四八):ActionBar(1):Home图标区 2013年03月10日 ? 综合 ? 共 3256字 ? 字号 小 中 大 ? 评论关闭 ActionBar在Android 3.0 SDK中为平板引入,在4.0中也可以在phone中使用.在title中提供类似tab和菜单的效果,有三种形式:Tabbed action bar,list action bar和standard action bar,我们将在小例子中进行示范. Home Icon 在Actio