`

ScrollView与ListView冲突解决

 
阅读更多

正常来说,在ScrollView添加一个ListView后在真机上只会显示ListView的一行多一点,我也不理解为什么会这样,后来我把 ListView的layout_height改成400dip,而不是用match_parent和wrap_content,我发现这样的话 ListView就显示的多了很多。所以就产生了把ListView所有的item的高度算出来给ListView设置的想法。下面是代码:

    public void setListViewHeightBasedOnChildren(ListView listView) {  
            ListAdapter listAdapter = listView.getAdapter();   
            if (listAdapter == null) {  
                return;  
            }  
      
            int totalHeight = 0;  
            for (int i = 0; i < listAdapter.getCount(); i++) {  
                View listItem = listAdapter.getView(i, null, listView);  
                listItem.measure(0, 0);  
                totalHeight += listItem.getMeasuredHeight();  
            }  
      
            ViewGroup.LayoutParams params = listView.getLayoutParams();  
            params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));  
            params.height += 5;//if without this statement,the listview will be a little short  
            listView.setLayoutParams(params);  
        }  
 


在代码的倒数第二行二我又给加了5个像素,这是因为我在listview的属性里面添加了padding=5dip。
然后每次ListView的数据一有变化就用这个函数设置一下就好了,不过这样总感觉效率很低,希望有达人给指点一下。

简单来说就是把layout_height写死,这种办法也很适用于GridView(如果能估计得出GridView的高度的话)。


listview与ScrollView老问题的另类解法
http://www.eoeandroid.com/thread-42893-1-1.html
这几天一直被listview怎么合理的放进scorllview中的问题困扰,尝试过把listview放入scorllview中的朋友都知 道,被放入的listview显示是有问题的,无论怎么设置layout都只显示大概2行的高度,看起来很郁闷,更别说美观了,后来上网查询了一下,解决 方法有的是用linearlayout替换listview,还有修改onmeasure的,我比较懒个人感觉很麻烦不喜欢,终于想出了一个还算和谐的解 决方法:xml中的textlist设置如下:

<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:background="#44444444">
<ScrollView
     android:layout_width="fill_parent"
     android:layout_height="wrap_content">
    <LinearLayout
            android:id="@+id/ll1"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:scrollbars="vertical"
            android:orientation="vertical"
            android:paddingLeft="15dp"
            android:paddingRight="15dp"
            android:paddingTop="30dp"
            android:paddingBottom="30dp"
            android:background="#ff888888">
            <TextView
                    android:text="あ"
                    android:textColor="#ffeeeeee"
                    android:textSize="18sp"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"></TextView>
            <ListView
                    android:scrollbars="none"
                    android:stackFromBottom="true"
                    android:id="@+id/lv0"
                    android:layout_width="fill_parent"
                    android:layout_height="20dp"></ListView>
                    </LinearLayout>
</ScrollView>
</LinearLayout> 

 

其中的textview是我做的东西要用到的,和方法无关可以不看,然后就是在java中重新设置listview的高度了,目的是把listview“撑”开:
LinearLayout.LayoutParams  lp5 =new LinearLayout.LayoutParam(LayoutParams.FILL_PARENT, listItem.size()*51-1);
其中第一个属性不必说了,第二个是为了计算listview要设置的总高度用的,51是我事先设置好的一行的高度(50)+每行之间的间隔(1) 而得来的,listItem.size()是我要显示的行数,用.setLayoutParams(lp5);来重新设置高度,其他别的设置跟以前一样, 想要源码我整理完之后贴出来


如果不想写死 ,Android 解决ListView 和 ScrollView 共存冲突的问题
http://labs.chinamobile.com/mblog/532767_72693?wralxianxrnx
http://blog.liaoxiaoqi.com/?p=503

 

下面是我的一个实现 步骤:

  • 1、继承LinearLayout,既然会冲突那就不用ListView 改成线性布局做动态布局效果
  • 2、继承BaseAdapter ,可以参照一下Android app源码中 Widget 目录下的SimpleAdapter 为前面扩展的LinearLayout做数据。
  • 3、模拟数据填充扩展后的BaseAdapter 为扩展后的LinearLayout 加载数据

第一步:新建LinearLayoutForListView 类使其扩展LinearLayout重写以下两个方法:

 

   public LinearLayoutForListView(Context context) {
        super(context);
    }
    public LinearLayoutForListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

 

这两个方法可选,不过建议都写上,第一个方法可以让我们通过 编程的方式 实例化出来,第二个方法可以允许我们通过 XML的方式注册 控件,可以在第二个方法里面为扩展的复合组件加属性。为其添加get / set 方法

   /**
     * 获取Adapter
     * 
     * @return adapter
     */
    public AdapterForLinearLayout getAdpater() {
        return adapter;
    }

    /**
     * 设置数据
     * 
     * @param adpater
     */
    public void setAdapter(AdapterForLinearLayout adpater) {
        this.adapter = adpater;
        bindLinearLayout();
    }

    /**
     * 获取点击事件
     * 
     * @return
     */
    public OnClickListener getOnclickListner() {
        return onClickListener;
    }

    /**
     * 设置点击事件
     * 
     * @param onClickListener
     */
    public void setOnclickLinstener(OnClickListener onClickListener) {
        this.onClickListener = onClickListener;
    }
 

第二步:新建AdapterForLinearLayout 类继承自BaseAdapter,并为其添加构造函数

 

 

private LayoutInflater mInflater;
    private int resource;
    private List<? extends Map<String, ?>> data;
    private String[] from;
    private int[] to;

    public AdapterForLinearLayout(Context context,
            List<? extends Map<String, ?>> data, int resouce, String[] from,
            int[] to) {
        this.data = data;
        this.resource = resouce;
        this.data = data;
        this.from = from;
        this.to = to;
        this.mInflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

 

此构造函数模仿 simpleAdapter 通过传进来的resouce 为布局设置数据。通过继承BaseAdapter 重要的实现方法在下面getView ,此方法判断通过传进来的 String[] from 与 int[] to 为分别查找出View 并为View 设置相应的Text,代码如下:

 

 

   @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub

        convertView = mInflater.inflate(resource, null);
        Map<String, ?> item = data.get(position);
        int count = to.length;
        for (int i = 0; i < count; i++) {
            View v = convertView.findViewById(to[i]);
            bindView(v, item, from[i]);
        }
        convertView.setTag(position);
        return convertView;
    }

    /**
     * 绑定视图
     * @param view
     * @param item
     * @param from
     */
    private void bindView(View view, Map<String, ?> item, String from) {
        Object data = item.get(from);
        if (view instanceof TextView) {
            ((TextView) view).setText(data == null ? "" : data.toString());
        }
    }

 

Tip:

  • BindView 方法是一个自定义方法,在方法体内可以为通过判断使本类更具灵活性,如上,你不仅可以判断是TextView 并且可以传入任何你想要的View 只要在方法体内加入相应判断即可,数据可以通过data 做相应处理,具体如何操作读者可另行测试。
  • convertView.setTag(position); 此句代码为View 设置tag 在以后我们可以通过 getTag 找出下标,后文有介绍如何通过下标操作数据。

下面是两个类的全部代码,读者可以无须更改直接使用:

LinearLayoutForListView
package  com.terry.widget;

import  android.content.Context;
import  android.util.AttributeSet;
import  android.util.Log;
import  android.view.View;
import  android.widget.LinearLayout;

public   class  LinearLayoutForListView  extends  LinearLayout {
     private  AdapterForLinearLayout adapter;
     private  OnClickListener onClickListener  =   null ;

     /**
     * 绑定布局
      */
     public   void  bindLinearLayout() {
         int  count  =  adapter.getCount();
         for  ( int  i  =   0 ; i  <  count; i ++ ) {
            View v  =  adapter.getView(i,  null ,  null );

            v.setOnClickListener( this .onClickListener);
             if  (i  ==  count  -   1 ) {
                LinearLayout ly  =  (LinearLayout) v;
                ly.removeViewAt( 2 );
            }
            addView(v, i);
        }
        Log.v( " countTAG " ,  ""   +  count);
    }

     public  LinearLayoutForListView(Context context) {
         super (context);
    }

     public  LinearLayoutForListView(Context context, AttributeSet attrs) {
         super (context, attrs);
    }

     /**
     * 获取Adapter
     * 
     *  @ return  adapter
      */
     public  AdapterForLinearLayout getAdpater() {
         return  adapter;
    }

     /**
     * 设置数据
     * 
     *  @ param  adpater
      */
     public   void  setAdapter(AdapterForLinearLayout adpater) {
         this .adapter  =  adpater;
        bindLinearLayout();
    }

     /**
     * 获取点击事件
     * 
     *  @ return
      */
     public  OnClickListener getOnclickListner() {
         return  onClickListener;
    }

     /**
     * 设置点击事件
     * 
     *  @ param  onClickListener
      */
     public   void  setOnclickLinstener(OnClickListener onClickListener) {
         this .onClickListener  =  onClickListener;
    }
}

 

 

AdapterForLinearLayout
package  com.terry.widget;

import  java.util.List;
import  java.util.Map;

import  android.content.Context;
import  android.view.LayoutInflater;
import  android.view.View;
import  android.view.ViewGroup;
import  android.widget.BaseAdapter;
import  android.widget.TextView;

public   class  AdapterForLinearLayout  extends  BaseAdapter {

     private  LayoutInflater mInflater;
     private   int  resource;
     private  List <?   extends  Map < String,  ?>>  data;
     private  String[] from;
     private   int [] to;

     public  AdapterForLinearLayout(Context context,
            List <?   extends  Map < String,  ?>>  data,  int  resouce, String[] from,
             int [] to) {
         this .data  =  data;
         this .resource  =  resouce;
         this .data  =  data;
         this .from  =  from;
         this .to  =  to;
         this .mInflater  =  (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    @ Override
     public   int  getCount() {
         //  TODO Auto-generated method stub
         return  data.size();
    }

    @ Override
     public  Object getItem( int  position) {
         //  TODO Auto-generated method stub
         return  data.get(position);
    }

    @ SuppressWarnings( " unchecked " )
     public  String get( int  position, Object key) {
        Map < String,  ?>  map  =  (Map < String,  ?> ) getItem(position);
         return  map.get(key).toString();
    }

    @ Override
     public   long  getItemId( int  position) {
         //  TODO Auto-generated method stub
         return  position;
    }

    @ Override
     public  View getView( int  position, View convertView, ViewGroup parent) {
         //  TODO Auto-generated method stub

        convertView  =  mInflater.inflate(resource,  null );
        Map < String,  ?>  item  =  data.get(position);
         int  count  =  to.length;
         for  ( int  i  =   0 ; i  <  count; i ++ ) {
            View v  =  convertView.findViewById(to[i]);
            bindView(v, item, from[i]);
        }
        convertView.setTag(position);
         return  convertView;
    }

     /**
     * 绑定视图
     *  @ param  view
     *  @ param  item
     *  @ param  from
      */
     private   void  bindView(View view, Map < String,  ?>  item, String from) {
        Object data  =  item.get(from);
         if  (view  instanceof  TextView) {
            ((TextView) view).setText(data  ==   null   ?   ""  : data.toString());
        }
    }
}

 

对应的XML 如下:

<? xml version="1.0" encoding="UTF-8" ?>
< LinearLayout  xmlns:android ="http://schemas.android.com/apk/res/android"
    android:orientation ="vertical"  android:layout_width ="fill_parent"
    android:layout_height ="fill_parent" >
     < TextView  android:id ="@ +id/TextView01"
        android:layout_marginLeft ="10px"  android:textAppearance ="?android:attr/textAppearanceLarge"
        android:layout_width ="wrap_content"  android:layout_height ="wrap_content" >
     </ TextView >
     < TextView  android:id ="@ +id/TextView02"  android:layout_width ="wrap_content"
        android:textAppearance ="?android:attr/textAppearanceSmall"
        android:layout_marginLeft ="10px"  android:layout_height ="wrap_content" >
     </ TextView >
     < View  android:layout_height ="1px"  android:background ="#FFFFFF"
        android:layout_width ="fill_parent" ></ View >
</ LinearLayout >

 

第三步:主页面使用控件并为其设置数据

  • XML如下:
       
    < com.terry.widget.LinearLayoutForListView
              android:orientation ="vertical"  android:layout_width ="450px"
               android:layout_height ="fill_parent"  android:id ="@ +id/ListView01" >
    </ com.terry.widget.LinearLayoutForListView > 
    
    
  • 加载数据如下:
    lv  =  (LinearLayoutForListView) findViewById(R.id.ListView01);
             for  ( int  i  =   0 ; i  <   10 ; i ++ ) {
                HashMap < String, Object >  map  =   new  HashMap < String, Object > ();
                map.put( " key_name " ,  " name "   +  i);
                map.put( " value_name " ,  " value "   +  i);
                list.add(map);
            }
    
             final  AdapterForLinearLayout Layoutadpater  =   new  AdapterForLinearLayout(
                     this , list, R.layout.test,  new  String[] {  " key_name " ,
                             " value_name "  },  new   int [] { R.id.TextView01,
                            R.id.TextView02 });
    
  • 事件操作,并通过下标得到数据源:
    lv.setOnclickLinstener( new  OnClickListener() {
    
                @ Override
                 public   void  onClick(View v) {
                     //  TODO Auto-generated method stub
                    Toast.makeText(
                            BlueToothActivity. this ,
                            Layoutadpater.get(Integer.parseInt(v.getTag()
                                    .toString()),  " key_name " ),  1000 ).show();
                }
            });
    lv.setAdapter(Layoutadpater);
    
    Tip:get方法是在Layoutadpater 封装的一个通过下标获取相应数据的方法请参考上文。

至此完成。有碰到这个问题的朋友可以试试。

 

有人的总结如下:
      只要在设置ListView的Adapter后调用此静态方法即可让ListView正确的显示在其父ListView的ListItem中。但是要注意 的是,子ListView的每个Item必须是LinearLayout,不能是其他的,因为其他的Layout(如RelativeLayout)没有 重写onMeasure(),所以会在onMeasure()时抛出异常。
  在ScrollView中嵌套ListView(或者ScrollView)的另外一个问题就是,子ScrollView中无法滑动的(如果它没有显 示完全的话),因为滑动事件会被父ScrollView吃掉,如果想要让子ScrollView也可以滑动,只能强行截取滑动事件,有牛人在论坛 中发过代码说可以。虽然我没有亲自试过,但估计是可行的。
  虽然在ScrollView中显示ScrollView在技术上的难题可以攻破,但是这样的设计却是非常差的用户体验因为用户会不容易看到和操作子 ScrollView中的内容。比如好的设计是,父ListView的每个Item只显示概括性的描述,然后点击其Item会进入另外一个页面来详细描述 和展示以及对这个Item的操作。
 
于是找到另外两种比较简单的方法,而且又没有影响的:
1.在ScrollView中添加一属性 android:fillViewport="true" ,这样就可以让ListView全屏显示了
2.指定ListView的高度 android:layout_height="420dp" ;

 

分享到:
评论
6 楼 guimingxing 2012-10-19  
5 楼 guimingxing 2012-10-19  
4 楼 mykeys 2012-09-07  
这个我试了,不知道怎么加载更多数据,用notifyDataSetChanged()根本就不会刷新调用getView,楼主是否能解决这个问题
3 楼 sgjsdf5944 2012-08-24  
楼主你好,如果是你说的自定义控件继承LinearLayout,那么我想要android:divider="#0000"
android:dividerHeight="10dip"这些属性怎么办,而且如何实现动态数据分批加载如何实现,没有这些onScrollStateChanged,onScroll事件的,希望回复,谢谢!!!!!!!!!!!
2 楼 yanjunhui2011 2012-07-24  

http://download.csdn.net/detail/yanjunhui2011/4444300
这里面是DEMO。。。。
1 楼 龙哥IT 2011-11-24  
这个案例改成动态加载分页看看啥

相关推荐

    解决scrollView和listview滚动冲突,实现listview滑动到顶端和底部之后还能拖拽一定的距离,松开后返回

    可以将原始的ScrollView替换为NestedScrollView,然后直接在其中添加ListView,通常可以避免大部分冲突。 接下来,我们要实现ListView滑动到底部或顶部后还能继续拖拽一段距离,松手后自动回弹的效果。这可以通过...

    Android解决ScrollView和ListView冲突问题Demo

    本Demo通过自定义ListView,实现了在ScrollView中嵌套ListView而不发生冲突的效果,从而提供了一种有效的解决方案。通过学习和实践这个Demo,开发者可以更深入地理解Android布局组件的交互,并能更好地处理类似的...

    scrollview嵌套listview冲突解决

    2. **冲突的滚动行为**:ScrollView本身具有滚动功能,而ListView也有自己的滚动逻辑。当用户试图滚动ListView时,可能会触发ScrollView的滚动,导致用户体验下降。 解决这些问题的方法有以下几种: 1. **使用...

    ScrollView与ListView的滑动冲突

    ### ScrollView与ListView的滑动冲突解决方案 在Android开发过程中,我们经常会遇到ScrollView与ListView或GridView组合使用时出现的滑动冲突问题。这类问题通常表现为:当ScrollView内部包含一个ListView或...

    ScrollView+ListView冲突问题完美解决

    综上所述,解决ScrollView和ListView冲突问题需要理解它们的工作原理,并根据实际情况选择合适的方法。通过自定义组件、优化事件处理以及使用更合适的布局组件,我们可以有效地解决这些问题,从而提供更好的用户体验...

    解决Scrollview嵌套listview下拉刷新的一些问题

    由于ScrollView和ListView都具有滚动功能,它们之间可能会出现滑动冲突。当你尝试滑动ListView时,ScrollView可能也会尝试滚动,导致用户体验不佳。 **解决方案**: 1. 设置ListView的`android:...

    Android中自定义ListView,解决scrollview嵌套listview 滑动事件冲突

    总之,解决ScrollView与ListView滑动事件冲突的关键在于正确处理触摸事件的分发,确保每个组件都能在合适的时候接收并处理滑动事件。通过自定义组件或者利用现有组件的特性,我们可以构建出更加符合用户体验的界面。...

    scrollview与listview,viewpager共存

    解决ScrollView与ListView、ViewPager共存的问题,有以下几种策略: 1. **避免嵌套**:最佳实践是尽量避免在ScrollView中嵌套可滚动的视图。如果需要展示的内容可以分为多个部分,考虑使用多个单独的ScrollView,...

    解决ScrollView嵌套ListView Demo

    通过上述方式,我们可以有效地解决ScrollView嵌套ListView的滚动冲突问题,使得两者能够协同工作,提供良好的用户体验。在"demo"项目中,你可以找到一个实际的应用示例,通过运行和调试,更深入地理解这个解决方案的...

    ScrollView_ListView 事件冲突

    ScrollView_ListView 事件冲突

    android中scrollview与listview共存

    解决方法是在ListView内部使用一个独立的ScrollView,或者使用嵌套滚动(NestedScrolling)API,如NestedScrollView,它能够更好地处理嵌套滚动场景。 2. **性能问题**:由于ScrollView会尝试加载其所有子视图,这...

    ScrollView嵌套ListView滑动冲突的解决方法

    在Android开发中,ScrollView和ListView是两种常用的布局组件。ScrollView是一个可以包含单个直接子视图的滚动容器,而...通过合理的设计和代码实现,可以有效地避免ScrollView与ListView的滑动冲突,提高用户体验。

    ScrollView和ListView和GridView冲突解决

    本篇文章将深入探讨如何解决ScrollView与ListView、GridView之间的冲突问题。 首先,ScrollView是一个可以包含单个直接子视图的布局,它允许用户滚动内容,当内容超过屏幕大小时尤其有用。然而,ScrollView不支持...

    ScrollView嵌套ListVIew两者之间滑动问题

    总之,处理ScrollView与ListView之间的滑动冲突是Android开发中的常见挑战,理解滑动事件的处理流程和利用提供的API或自定义逻辑,是解决问题的关键。通过以上所述的方法,开发者能够有效地解决这种冲突,实现流畅的...

    解决ScrollView,ListView滚动条冲突

    本篇文章将详细讲解如何解决ScrollView与ListView滚动条冲突,并将这一解决方案扩展到其他具有滚动条的控件。 首先,我们来理解问题的本质。ScrollView是一个可以包含多个子视图的垂直滚动容器,而ListView则是一个...

    解决scrollview嵌套listview的冲突问题

    用于解决scrollview组件嵌套listview组件时候 两者之间的冲突问题

    android 解决ScrollView和listView嵌套冲突问题(保证在ScrollView中滑动listView只响应listView的滑动)

    本篇将详细介绍如何解决这种冲突,确保在ScrollView中滑动ListView时,只响应ListView的滑动。 首先,我们要理解ScrollView和ListView的工作原理。ScrollView是一个可滚动的布局容器,它可以包含一个或多个视图,并...

    ScrollView嵌套ListView刷新

    NestedScrollView解决了直接嵌套ListView导致的冲突问题,同时保持了ScrollView的功能。 2. **使用Header和Footer**:如果只是想在ListView顶部或底部添加一个固定的ScrollView,可以考虑使用ListView的...

    Android ScrollView嵌套ListView嵌套GridView的上下拉以及加载更多

    然而,由于ScrollView自身并不支持滚动事件的监听,因此当我们在ScrollView中嵌套可滚动的组件如ListView或GridView时,可能会遇到滚动冲突问题。为了解决这个问题,开发者需要手动处理滚动事件,或者选择使用如...

    自定义ScrollView与ListView结合使用

    总之,理解和掌握ScrollView与ListView的结合使用及其问题解决是Android开发中的一个重要技能。自定义这两个组件可以帮助我们实现更多功能,提高应用的用户体验,同时也锻炼了我们的编程能力和问题解决能力。

Global site tag (gtag.js) - Google Analytics