ListView的条目滑动删除效果。
原理:
1、利用onTouchListener方法获取手指触摸的点的坐标。
2、利用ListView的pointToPosition方法获取当前获得焦点的条目在ListView中的position
3、利用Animation播放滑动的动画。
4、利用AnimationListener可以监听到动画播放开始,重复和解说事件。我们要在结束时删除条目。
布局和动画都很简单,只有删除条目和获取播放动画的条目两处有些容易出错,贴出代码后会说到这两个地方的小问题。
下面是布局代码:
界面布局activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ListView
android:id="@+id/lv"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
</ListView>
</LinearLayout>
ListView的条目item.xml
<?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" >
<TextView
android:id="@+id/tv"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:paddingLeft="10dp"
android:textColor="#FF0000"
android:textSize="40dp" />
</LinearLayout>
动画 delete.xml
<?xml version="1.0"encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="1000"
android:fromXDelta="0%"
android:interpolator="@android:anim/accelerate_interpolator"
android:toXDelta="100%"/>
</set>
界面代码和适配器代码在同一个java文件中 MainActivity.java
package com.example.listviewdemo;
import java.util.ArrayList;
import java.util.List;
import com.example.listviewdemo.R;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnTouchListener;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationUtils;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.app.Activity;
import android.content.Context;
public classMainActivity extends Activity implements OnTouchListener,
AnimationListener{
public List<String> list = newArrayList<String>();
private ListView lv;
private StringAdapter adapter;
private int pointX, pointY, endX;
private int position;
@Override
public void onCreate(BundlesavedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv = (ListView)findViewById(R.id.lv);
adapter = new StringAdapter(this);
lv.setAdapter(adapter);
lv.setOnTouchListener(this);
}
@SuppressWarnings("static-access")
@Override
public boolean onTouch(View v,MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 手指按下,计算焦点位于ListView的那个条目
pointX = (int) event.getX();
pointY = (int) event.getY();
// 备注1
position = lv.pointToPosition(pointX, pointY);
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
endX = (int) event.getX();
if (endX - pointX > 300) {
// 获取到ListView第一个可见条目的position
int firstVisiblePosition = lv.getFirstVisiblePosition();
// 删除条目的动画
AnimationUtilsutils = newAnimationUtils();
Animationanimation = utils.loadAnimation(MainActivity.this,
R.anim.delete);
animation.setAnimationListener(this);
// --------------备注2
Viewview = lv.getChildAt(position -firstVisiblePosition);
try {
view.startAnimation(animation);
}catch(NullPointerException e) {
Log.i("MainActivity","报个空指针异常!");// --------------备注3
}
}
break;
default:
break;
}
return false;
}
@Override
public voidonAnimationEnd(Animation animation) {
// 使用List集合的remove方法移除掉第position个元素,然后通知适配器重新适配数据。
try {
list.remove(position);
}catch(ArrayIndexOutOfBoundsException e) {
Log.i("MainActivity","报个数组越界异常! position =" + position);// --------------备注4
}
adapter.notifyDataSetChanged();
}
@Override
public voidonAnimationRepeat(Animation animation) {
}
@Override
public voidonAnimationStart(Animation animation) {
}
public class StringAdapter extends BaseAdapter {
private LayoutInflater inflater;
private String content = "";
public StringAdapter(Contextcontext) {
inflater = LayoutInflater.from(context);
for (int i = 0; i < 20; i++){
content = "item "+ i;
list.add(content);
}
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, ViewconvertView, ViewGroup parent) {
if (convertView == null) {
convertView= inflater.inflate(R.layout.item, null);
}
TextViewtv = (TextView) convertView.findViewById(R.id.tv);
tv.setText(getItem(position)+ "");
return convertView;
}
}
}
关键代码解释:
备注1:根据手指触摸点的坐标计算ListView的那个条目获得了焦点。这里得到的position是相对于整个ListView而说。这里很重要。
备注2:getChildAt(int position)方法中的形参position是以当前ListView的可视区域确定的。与 备注1中的position完全没有关系。所以这里使用的不能是position,而应该是position减去第一个可见条目的position。
备注3 和备注 4:我自己捕获的异常。如果删除动作很快很频繁而且ListView条目很多时,这里会抛出两个异常。
完