android中ListView使用最为频繁,但是同时出现问题也是最多的,下面就总结一下我在开发中遇到的问题,

问题一:在自定义添加adapter中添加button,或是checkBox时无法同时响应setOnItemClickListener事件中的item click 事件和控件本身点击事件

item 原布局文件;


<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent" android:layout_height="wrap_content"><Buttonandroid:id="@+id/array_button"android:layout_width="wrap_content" android:layout_height="wrap_content"    android:text="一个按钮"  /><ImageView android:id="@+id/array_image"android:layout_toRightOf="@+id/array_button"android:layout_width="wrap_content" android:layout_height="fill_parent"android:layout_alignParentTop="true" android:layout_alignParentBottom="true"android:adjustViewBounds="true"android:padding="2dip" /><TextView android:id="@+id/array_title"android:layout_width="fill_parent" android:layout_height="wrap_content"android:layout_toRightOf="@+id/array_image"android:layout_alignParentBottom="true"android:layout_alignParentRight="true" android:singleLine="true"android:ellipsize="marquee" android:textSize="15dip"  /><TextView android:id="@+id/array_text"android:layout_width="fill_parent" android:layout_height="wrap_content"android:layout_toRightOf="@+id/array_image"android:layout_below="@+id/array_title"android:layout_alignParentBottom="true"android:layout_alignParentRight="true" android:singleLine="true"android:ellipsize="marquee" android:textSize="20dip" /></RelativeLayout>


重写的adapter:

public View getView(final int position, View convertView, ViewGroup parent) {    ImageView iamge = null;    TextView title = null;    TextView text = null;    Button button = null;    if (convertView == null) {convertView = LayoutInflater.from(mContext).inflate(mTextViewResourceID, null);iamge = (ImageView) convertView.findViewById(R.id.array_image);title = (TextView) convertView.findViewById(R.id.array_title);text = (TextView) convertView.findViewById(R.id.array_text);button = (Button)convertView.findViewById(R.id.array_button);button.setOnClickListener(new OnClickListener() {        @Override    public void onClick(View arg0) {Toast.makeText(arrayList,"您点击的第"+position +"个按钮", Toast.LENGTH_LONG).show();    }});    }    }


解决方法:只要在item布局文件中添加android:descendantFocusability="blocksDescendants" 属性,

在添加的控件添加属性

android:clickable="true"
android:focusable="false"

更改后的item布局文件内容:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent" android:layout_height="wrap_content"android:descendantFocusability="blocksDescendants"><Buttonandroid:id="@+id/array_button"android:layout_width="wrap_content" android:layout_height="wrap_content"    android:text="一个按钮"    android:clickable="true"    android:focusable="false"/><ImageView android:id="@+id/array_image"android:layout_toRightOf="@+id/array_button"android:layout_width="wrap_content" android:layout_height="fill_parent"android:layout_alignParentTop="true" android:layout_alignParentBottom="true"android:adjustViewBounds="true"android:padding="2dip" /><TextView android:id="@+id/array_title"android:layout_width="fill_parent" android:layout_height="wrap_content"android:layout_toRightOf="@+id/array_image"android:layout_alignParentBottom="true"android:layout_alignParentRight="true" android:singleLine="true"android:ellipsize="marquee" android:textSize="15dip"  /><TextView android:id="@+id/array_text"android:layout_width="fill_parent" android:layout_height="wrap_content"android:layout_toRightOf="@+id/array_image"android:layout_below="@+id/array_title"android:layout_alignParentBottom="true"android:layout_alignParentRight="true" android:singleLine="true"android:ellipsize="marquee" android:textSize="20dip" /></RelativeLayout>

问题二:如何再点击item时获取item内子对象,根据适当条件改变其属性内容

例如单击item选项后改变这条item背景色

解决方法:使用adapterView.getChildAt(index)方法

mListView.setOnItemClickListener(new OnItemClickListener() {    @Override    public void onItemClick(AdapterView<?> adapterView, View view, int position,    long id) {View v=adapterView.getChildAt(position);v.setBackgroundColor(Color.RED);    }});

看上去好像可以了,但是以上方法只是用于数据没有滚动时即可见区域内

当数据量很大时,即开始滑动是再点击会发生adapterView.getChildAt(index)获取view为空

这时就需要另一个方法adapterView.getFirstVisiblePosition();获取第一个可见item位置,使用当前position-这个位置

具体实现View v=adapterView.getChildAt(pos-adapterView.getFirstVisiblePosition());


判断adapter内数据第一次出现加载:

根据getView中的position判断是否大于mLastAnimatedPosition,如果大于mLastAnimatedPosition则为第一次

private int mLastAnimatedPosition= -1;boolean firstLoadData(int pos){boolean isFirst=false;if(pos>mLastAnimatedPosition){isFirst=true;this.mLastAnimatedPosition=pos;}return isFirst;}

Listview 定位,恢复ListView上次的视图位置:

ListView mListView;int backIndex,backTop;//保存item view  index,偏移量void saveListViewPositionView(){backIndex=mListView.getFirstVisiblePosition();View v=mListView.getChildAt(0);backTop=(v==null) ? 0:v.getTop();}//根据上次保存index,偏移量恢复视图void restoreListViewPositionView(){mListView.setSelectionFromTop(backIndex, backTop);}

其实还可以使用setSelection也可以定位,只是setSelectionFromTop要比setSelection更精准。因为通过getFirstVisiblePosition得到的第一个item可能已经有一部分是不可见的了,如果用setSelection无法反映出这不可见的部分。

还可以使用带有滚动过程带有动画效果方式:

mListView.smoothScrollBy("distance",duration);mListView.smoothScrollToPosition(position);


Listview 添加HeaderView时,设置指定大小值:

ImageView imageHeaderView = new ImageView(this);imageHeaderView.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.deckblatt));imageHeaderView.setScaleType(ScaleType.CENTER_CROP);imageHeaderView.setLayoutParams(new AbsListView.LayoutParams(100, 100));  myList.addHeaderView(imageHeaderView);

值得注意的LayoutParams必须为AbsListView.LayoutParams才能生效,不然程序奔溃,无效。

HeaderView设置隐藏时Gone还会有占位,需要remove或者增加了一个多余的Layout(item_container)来囊括item内部控件。此时,如果在item_container .setVisibility(View.GONE)则可以完美实现隐藏HeaderView的目的!


ListView设置Selector为空

mListView.setSelector(null);//空指针

mListView.setSelector(newColorDrawable(Color.TRANSPARENT));


ListView及item焦点问题:

mListView.requestFocusFromTouch();

這時你需要在你的xml文件中对些控件添加android:focusable=false;

ListView的右边滚动滑块启用

使用XML布局只需要在 ListView节点中加入android:fastScrollEnabled="true" 这个属性即可,

而对于Java代码可以通过myListView.setFastScrollEnabled(true); 来控制启用,参数false为隐藏。
还有一点就是当你的滚动内容较小,不到当前ListView的3个屏幕高度时则不会出现这个



listview 中几个实用的属性:

去掉ListView Selector选种时黄色底纹一闪的效果

<?xmlversion="1.0" encoding="utf-8"?>

<shapexmlns:android="http://schemas.android.com/apk/res/android">

<solidandroid:color="@android:color/transparent"/>

<cornersandroid:radius="0dip" />

</shape>

//listview.setSelector(R.drawable.thisShape);


Listview右边滚动条始终显示

xml文件中做如下修改 android:fadeScrollbars="false"

stackFromBottom属性,这只该属性之后你做好的列表就会显示你列表的最下面,值为true和false
android:stackFromBottom="true"

transciptMode属性,需要用ListView或者其它显示大量Items的控件实时跟踪或者查看信息,并且希望最新的条目可以自动滚动到可视范围内。通过设置的控件transcriptMode属性可以将Android平台的控件(支持ScrollBar)自动滑动到最底部。
android:transcriptMode="alwaysScroll"

cacheColorHint属性,很多人希望能够改变一下它的背景,使他能够符合整体的UI设计,改变背景背很简单只需要准备一张图片然后指定属性 android:background="@drawable/bg",不过不要高兴地太早,当你这么做以后,发现背景是变了,但是当你拖动,或者点击list空白位置的时候发现ListItem都变成黑色的了,破坏了整体效果。

如果你只是换背景的颜色的话,可以直接指定android:cacheColorHint为你所要的颜色,如果你是用图片做背景的话,那也只要将android:cacheColorHint指定为透明(#00000000)就可以了

divider属性,该属性作用是每一项之间需要设置一个图片做为间隔,或是去掉item之间的分割线
android:divider="@drawable/list_driver" 其中 @drawable/list_driver 是一个图片资源,如果不想显示分割线则只要设置为android:divider="@drawable/@null" 就可以了

fadingEdge属性,上边和下边有黑色的阴影
android:fadingEdge="none" 设置后没有阴影了~

scrollbars属性,作用是隐藏listView的滚动条,
android:scrollbars="none"与setVerticalScrollBarEnabled(true);的效果是一样的,不活动的时候隐藏,活动的时候也隐藏

fadeScrollbars属性,android:fadeScrollbars="true" 配置ListView布局的时候,设置这个属性为true就可以实现滚动条的自动隐藏和显示。


LIstView局部刷新View处理:(How can I update a single row in a ListView?)

private void updateItemView(int index,boolean selected){        View vitem = mListView.getChildAt(index -                mListView.getFirstVisiblePosition());        CheckBox checkStore=(CheckBox)vitem.findViewById(R.id.shop_title_checkbox);        checkStore.setChecked(selected);vitem.invalidate();    }


控制listview滚动速度

// scroll speed decreases as friction increases. a value of 2 worked
getListView().setFriction(ViewConfiguration.getScrollFriction() * 2);

// 因子越大滚动越慢 ,只有API>11时可以使用(Verified that this works really nicely for API >= 11:)


headerView or footview问题

在添加和删除HeaderView之前,先执行mListView.setAdapter()不然报错,这个问题在低于4.0以前版本会有这个问题,4.0之后在哪里add都可以

headerView or footview 在设置为gone时还会有展位情况,解决方法:反复执行remove,add,这样在一定程度上影响效率,可以在嵌套一层可以解决

<?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="wrap_content"    android:orientation="vertical" >    <!-- @color/shop_cart_order_pref_bg_color -->    <RelativeLayout        android:id="@+id/rl"        android:layout_width="match_parent"        android:layout_height="40dip"        android:gravity="center_vertical"        android:paddingLeft="10dp"        android:paddingRight="10dp" >        <TextView            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:layout_alignParentLeft="true"            android:drawablePadding="5dp"            android:drawableRight="@drawable/jiantou"            android:text="@string/nologin_tipe"            android:textColor="#999999"            android:textSize="12sp" />    </RelativeLayout></LinearLayout>
 操作里面的id=rl布局gone即可占位消除(此问题也可用于解决listview 中的item部分内容隐藏占位问题)  

速度计算处理方式 (1,GestureDetector.SimpleOnGestureListener onFling处理,也可以使用速度计算VelocityTracker实现)

VelocityTrackingTouchListener mTouchListener;    GestureDetector mGestureDetector;    void initTouchLis(View v){    // Instantiate a gesture listener to consume scroll and fling events    FlingDetector flingDetector = new FlingDetector();    // Pass the FlingDetector to mGestureDetector to receive the appropriate callbacks    mGestureDetector = new GestureDetector(this, flingDetector);    mTouchListener = new VelocityTrackingTouchListener();    v.setOnTouchListener(mTouchListener);    }        class VelocityTrackingTouchListener implements View.OnTouchListener {    private VelocityTracker mVelocityTracker;private int mPointerId;private float xVelocity,yVelocity;        @Override        public boolean onTouch(View view, MotionEvent motionEvent) {        switch (motionEvent.getAction()) {            case MotionEvent.ACTION_DOWN:                if (mVelocityTracker == null) {                    // Retrieve a new VelocityTracker object to watch the velocity of a motion.                    mVelocityTracker = VelocityTracker.obtain();                } else {                    // Reset the velocity tracker back to its initial state.                    mVelocityTracker.clear();                }                // Add a user's movement to the tracker.                mVelocityTracker.addMovement(motionEvent);        //求第一个触点的id, 此时可能有多个触点,但至少一个                mPointerId = motionEvent.getPointerId(0);             break;            case MotionEvent.ACTION_MOVE:                mVelocityTracker.addMovement(motionEvent);                // When you want to determine the velocity, call                // computeCurrentVelocity(). Then call getXVelocity()                // and getYVelocity() to retrieve the velocity for each pointer ID.                mVelocityTracker.computeCurrentVelocity(1000);                // Log velocity of pixels per second                xVelocity = mVelocityTracker.getXVelocity(mPointerId);                yVelocity = mVelocityTracker.getYVelocity(mPointerId);            break;            case MotionEvent.ACTION_CANCEL:                // Return a VelocityTracker object back to be re-used by others.                mVelocityTracker.recycle();            break;        }            mGestureDetector.onTouchEvent(motionEvent);            return true;        }    }        class FlingDetector extends GestureDetector.SimpleOnGestureListener {        public FlingDetector() {            super();        }        @Override        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY) {        //    updateText("in onFling");            return true;        }        @Override        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {        //    updateText(String.format("onScroll velocity = (%f, %f)", mTouchListener.xVelocity, mTouchListener.yVelocity));                    return false;        }    }

ViewConfiguration的使用主要使用了该类的下面三个方法:
private final int TOUCH_SLOP = ViewConfiguration.get(getContext()).getScaledTouchSlop();
configuration.getScaledTouchSlop()//获得能够进行手势滑动的距离
configuration.getScaledMinimumFlingVelocity()//获得允许执行一个fling手势动作的最小速度值
configuration.getScaledMaximumFlingVelocity()//获得允许执行一个fling手势动作的最大速度值


持续更新中。。。




更多相关文章

  1. Android解决使用findViewById时需要对返回值进行类型转换问题的
  2. android 的Layout_weight属性
  3. .net基础初学Android
  4. Android之AndroidManifest.xml文件解析
  5. Android自定义View-圆形图片控件
  6. Android代码风格(Android属性前缀m的意思)
  7. android weight属性
  8. Android控件之文本控件---TextView 两种效果+SpannableString
  9. ScrollView内部嵌套Recyclerview,防止recyclerview自动获得焦点

随机推荐

  1. mysql MGR 单主多主模式切换知识点详解
  2. MySQL模式 Strict Mode知识点详解
  3. MySQL使用TEXT/BLOB类型的知识点详解
  4. linux 安装 mysql 8.0.19 详细步骤及问题
  5. Linux系统MySQL8.0.19快速安装配置教程图
  6. gearman + mysql方式实现持久化操作示例
  7. MySql分表、分库、分片和分区知识点介绍
  8. MySQL的DML语言操作实例
  9. mysql和oracle的区别小结(功能性能、选择
  10. MySQL全文索引、联合索引、like查询、jso