在ScrollView中使用ListView

     从原则上来说,不应该在一个可滚动的视图中再放置一个可滚动的视图,即滚动视图的嵌套。原因很简单,如果不加以限制,当移动事件发生时,触摸点处于有嵌套关系的多个滚动视图的交叠部分,安卓无法区分该事件应该由哪一个滚动视图消费所以,如果不是必须,可以使用其它的一些替代方式。比如用LinearLayout取代ListView放在一个ScrollView中,或者将ScrollView作为一个独立的View充当ListViewheader

     如果必须要进行嵌套,那么可以采用如下的方式:

ListView lv = (ListView)findViewById(R.id.listview); 
lv.setOnTouchListener(newListView.OnTouchListener() {
       @Override
       public boolean onTouch(View v, MotionEvent event) {
           int action = event.getAction();
           switch (action) {
           case MotionEvent.ACTION_DOWN:
               v.getParent().requestDisallowInterceptTouchEvent(true);
               break;
           case MotionEvent.ACTION_UP:
               v.getParent().requestDisallowInterceptTouchEvent(false);
                break;
           }
           v.onTouchEvent(event);
           return true;
        }
});


作为父控件的ScrollView重写了onInterceptTouchEvent方法,在其静止状态时是不拦截Action_Down事件的,此时在ListView所处区域触碰屏幕产生的Action_Down事件会顺利的传递给ListViewonDispatchTouchEvent,而ListView虽然是一个ViewGroup,但是使用的时候不会往里面放子视图,而是通过适配器来加载条目,所以ListViewAction_Down事件不会被子视图消费走,最终会回到ViewonDispatchTouchEvent,此时如果ListView上绑定了OnTouchListener,就会触发OnTouchListener里面的onTouch方法,并且如果onTouch方法返回true,就不会去执行ListViewonTouchEvent。所以,我们在onTouch里面要做三件事情:

1)  不允许作为父控件的ScrollView拦截任何事件

2)  手动调用自己的onTouchEvent方法。ListView重写了onTouchEvent方法,里面有大量自己的逻辑

3)  返回true

这样一来,所有的Action_Down后续事件都会经ScrollViewonDispatchToucEvent方法传递到ListViewOnTouchListener中来。只到收到了Action_Up事件,这意味着一次完整事件的结束,因此在遇到Action_Up事件时,要恢复ScrollView的拦截能力。

    这里还有一个额外的问题,就是ListViewScrollView中显示的高度,只有一行。如果需要调整,可以写一个工具方法:

public static voidsetListViewHeightBasedOnChildren(ListView listView) {
   ListAdapter listAdapter = listView.getAdapter();
    if(listAdapter == null)
       return;
int desiredWidth = MeasureSpec.makeMeasureSpec(
listView.getWidth(), MeasureSpec.UNSPECIFIED);
    inttotalHeight = 0;
    Viewview = null;
    for(int i = 0; i < listAdapter.getCount(); i++) {
       view = listAdapter.getView(i, view, listView);
       if (i == 0)
            view.setLayoutParams(
new ViewGroup.LayoutParams(
desiredWidth, LayoutParams.WRAP_CONTENT));
       view.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
       totalHeight += view.getMeasuredHeight();
    }
   ViewGroup.LayoutParams params = listView.getLayoutParams();
   params.height = totalHeight + (listView.getDividerHeight() *(listAdapter.getCount() - 1));
   listView.setLayoutParams(params);
   listView.requestLayout();
}


方法的作用就是将ListView的高度设定为可以一次性的将adapter中的所有条目都展示出来,通过设定LayoutParams来“覆盖”父控件原先分配的内容,设定自己希望的宽度和高度,设定完毕后申请一次重新布局。但是这样做完之后, ListView已经不用滚动机制了,因为它所有的内容都显示出来了,这样的ListView就好像一个“LinearLayout”,这么做实际上是摒弃了ListView的性能优点的。所以可以折中一下,为ListView提供一个指定的高度。

public static voidsetListViewHeightBasedOnChildren(ListView listView,int listviewHeight) {
              ListAdapterlistAdapter = listView.getAdapter();
              if(listAdapter == null)
                     return;
              ViewGroup.LayoutParamsparams = listView.getLayoutParams();
              params.height= listviewHeight;
              listView.setLayoutParams(params);
              listView.requestLayout();
}


通过该方法,可以将ListView的高度设置为我们指定的高度,比如屏幕高度的1/3

setListViewHeightBasedOnChildren(lv,getResources().getDisplayMetrics().heightPixels/3);


完整的MainActivity代码如下:

public class MainActivity extends Activity {
       privateListView lv;
       publicString[] strs ={"星期一","星期二","星期三","星期四","星期五","星期六","星期日","星期一","星期二","星期三","星期四","星期五","星期六","星期日","星期一","星期二","星期三","星期四","星期五","星期六","星期日"};
       publicstatic void setListViewHeightBasedOnChildren(ListView listView) {
              ListAdapterlistAdapter = listView.getAdapter();
              if(listAdapter == null)
                     return;
 
              intdesiredWidth = MeasureSpec.makeMeasureSpec(
                            listView.getWidth(),MeasureSpec.UNSPECIFIED);
              inttotalHeight = 0;
              Viewview = null;
              for(int i = 0; i < listAdapter.getCount(); i++) {
                     view= listAdapter.getView(i, view, listView);
                     if(i == 0)
                            view.setLayoutParams(newViewGroup.LayoutParams(
                                          desiredWidth,LayoutParams.WRAP_CONTENT));
                     view.measure(desiredWidth,MeasureSpec.UNSPECIFIED);
                     totalHeight+= view.getMeasuredHeight();
              }
              ViewGroup.LayoutParamsparams = listView.getLayoutParams();
              params.height= totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
              listView.setLayoutParams(params);
              listView.requestLayout();
       }
       publicstatic void setListViewHeightBasedOnChildren(ListView listView,int listviewHeight){
              ListAdapterlistAdapter = listView.getAdapter();
              if(listAdapter == null)
                     return;
              ViewGroup.LayoutParamsparams = listView.getLayoutParams();
              params.height= listviewHeight;
              listView.setLayoutParams(params);
              listView.requestLayout();
       }
 
       @Override
       protectedvoid onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
              lv= (ListView) findViewById(R.id.listview);
              lv.setAdapter(newArrayAdapter<String>(this, android.R.layout.simple_list_item_1,strs));
              lv.setOnTouchListener(newOnTouchListener() {
 
                     @Override
                     publicboolean onTouch(View v, MotionEvent event) {
                            intaction = event.getAction();
                            switch(action) {
                            caseMotionEvent.ACTION_DOWN:
                                   v.getParent().requestDisallowInterceptTouchEvent(true);
                                   break;
                            caseMotionEvent.ACTION_UP:
                                   v.getParent().requestDisallowInterceptTouchEvent(false);
                                   break;
                            }
                            v.onTouchEvent(event);
 
                            returntrue;
                     }
              });
              setListViewHeightBasedOnChildren(lv,getResources().getDisplayMetrics().heightPixels/3);
       }
 
       @Override
       publicboolean onCreateOptionsMenu(Menu menu) {
              //Inflate the menu; this adds items to the action bar if it is present.
              getMenuInflater().inflate(R.menu.main,menu);
              returntrue;
       }
 
}


布局文件如下:

<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="match_parent" >
 
   <ScrollView
       android:id="@+id/scrollview"
       android:layout_width="match_parent"
       android:layout_height="match_parent" >
 
       <LinearLayout
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:orientation="vertical" >
 
           <TextView
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:text="XXXXXXXXXXXXXXXXXXXXXXXX" />
 
           <TextView
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:text="XXXXXXXXXXXXXXXXXXXXXXXX" />
 
           <TextView
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:text="XXXXXXXXXXXXXXXXXXXXXXXX" />
 
           <ListView
               android:id="@+id/listview"
               android:layout_width="match_parent"
               android:layout_height="wrap_content" >
           </ListView>
            <TextView
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:text="XXXXXXXXXXXXXXXXXXXXXXXX" />
 
           <TextView
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:text="XXXXXXXXXXXXXXXXXXXXXXXX" />
 
            <TextView
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:text="XXXXXXXXXXXXXXXXXXXXXXXX" />
       </LinearLayout>
   </ScrollView>
 
</RelativeLayout>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值