ListView中开发问题汇总

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"
	>
	<Button
		android: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">
	<Button
		android: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手势动作的最大速度值


持续更新中。。。




posted @ 2012-11-28 13:14  HappyCode002  阅读(172)  评论(0编辑  收藏  举报