可拖动和删除动画的ListView

可拖动和删除动画的ListView,先看图:


如下是实现代码,懂得原理后,可自行修改。先大致说下原理:

拖动:

当长按后,生成被长按的条目(a)的影子,然后将长按的条目隐藏掉,当拖动时,判断当前滑动到的位置(b),然后让被长按的条目和拖动到的位置的数据进行交换,再刷新适配器就实现了拖动效果。

点击删除:

点击时,获取被点击的条目,然后开启属性动画,改变给View的高,当高变为近似为0时,在删除该条目(注意是近似为0二不是0,如果为0了,则是删不掉的)


其他的就不过多介绍,全在注释里:

《说明:布局文件就不上贴了,里面就是一个ListView而已。需要android.permission.SYSTEM_ALERT_WINDOW权限》


package com.lym.customview;


import java.util.ArrayList;
import java.util.List;
import java.util.Random;


import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.AbsListView.LayoutParams;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;


public class MainActivity extends Activity {


Handler handler = new Handler();
// private LayoutParams layoutParams;
private ListView listView;
private List<String> data;
private myAdapter adapter;
private WindowManager wm;

//当前是否是出于拖动状态(拖动状态是有影子显示的)
private boolean showShadow = false;


private View movedView = null;

//当前被移动的条目的位置
private int movedItemPosition;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);


listView = (ListView) findViewById(R.id.lv_listView);


wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);

//初始化ListView的数据
data = new ArrayList<String>();
for (int i = 0; i < 50; i++) {
data.add("条目" + (i + 1));
}


adapter = new myAdapter(this, data);
listView.setAdapter(adapter);

//点击事件
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
final int position, long id) {
//如果点击的是第一条,则增加条目,否则开启删除动画,兵删除条目
if (position == 0) {
Random random = new Random();
data.add("条目" + random.nextInt(1000));
adapter.notifyDataSetChanged();
} else {
View item = listView.findViewWithTag(position);
startAnimation(item, position);
}
}
});

//长按
listView.setOnItemLongClickListener(new OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view,
int position, long id) {
//获取长按的条目(这里我主要是通过设置tag来查找的)
movedView = listView.findViewWithTag(position);
//显示影子
showFloatWindow(movedView);
//隐藏掉被点击的条目(因为有影子了)
movedView.setVisibility(View.INVISIBLE);
movedItemPosition = position;
return true;
}
});


listView.setOnTouchListener(new OnTouchListener() {
private int startY;


@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//记录按下的位置
startY = (int) event.getY();
break;
case MotionEvent.ACTION_MOVE:
//如果是处于拖动状态
if (showShadow) {
int entY = (int) event.getY();
//获取y的位移
int dxY = entY - startY;
//更新影子的位置
updateFloatLocation(shadow, dxY);
//当前手指处在的位置对应的条目(-1表示没有在任何条目上)
int currPosition = listView.pointToPosition(
(int) event.getX(), (int) event.getY());
if (currPosition != -1
&& movedItemPosition != currPosition) {
//获取当前所处的条目和被拖动的条目,然后数据进行交换
String string = data.get(movedItemPosition);
String string2 = data.get(currPosition);
data.set(currPosition, string);
data.set(movedItemPosition, string2);
adapter.notifyDataSetChanged();
movedView.setVisibility(View.VISIBLE);
//重新获取被拖动的条目(注意影子并没有改变,所以视觉上任然感觉是原来被拖动的条目)
movedView = listView.getChildAt(currPosition);
movedView.setVisibility(View.GONE);
movedItemPosition = currPosition;
}
startY = entY;
}
break;
case MotionEvent.ACTION_UP:
if (showShadow) {
//移除影子
removeFloatView(shadow);
if (movedView != null) {
movedView.setVisibility(View.VISIBLE);
}
adapter.notifyDataSetChanged();
}
break;
default:
break;
}
return false;
}


});
}


private ImageView shadow;

//移除影子
public void removeFloatView(View view) {
if (showShadow) {
wm.removeView(view);
}
showShadow = false;
}


//更新影子的位置
public void updateFloatLocation(View view, int y) {
if (wmLayoutParams != null) {
wmLayoutParams.y += y;
wm.updateViewLayout(view, wmLayoutParams);
}
}


WindowManager.LayoutParams wmLayoutParams = null;

/**显示影子
 *
 *@param srcView 影子的源像的view
 */
private void showFloatWindow(View srcView) {
showShadow = true;
wmLayoutParams = new WindowManager.LayoutParams();
// 获取的是WindowManagerImpl.CompatModeWrapper
// 设置window type
wmLayoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
// 设置图片格式,效果为背景透明
wmLayoutParams.format = PixelFormat.TRANSLUCENT;
// 设置浮动窗口不可聚焦(实现操作除浮动窗口外的其他可见窗口的操作)
wmLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
// 调整悬浮窗显示的停靠位置为左侧置顶
wmLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
// 以屏幕左上角为原点,设置x、y初始值,相对于gravity
Rect rect = new Rect();
//获取源像的所在的矩形
srcView.getHitRect(rect);

//设置影子的左上角位置
wmLayoutParams.x = rect.left;
wmLayoutParams.y = rect.top;


// 设置悬浮窗口长宽数据
wmLayoutParams.width = srcView.getWidth();
wmLayoutParams.height = srcView.getHeight();

//将源像截图,作为影子
srcView.setDrawingCacheEnabled(true);
Bitmap bitmap = srcView.getDrawingCache();
shadow = new ImageView(this);
bitmap = Bitmap.createBitmap(bitmap);
shadow.setImageBitmap(bitmap);


shadow.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
return false;
}
});
//将影子加入到窗体中
wm.addView(shadow, wmLayoutParams);
}

//开启删除动画
public void startAnimation(final View view, final int position) {
final LayoutParams layoutParams = (LayoutParams) view.getLayoutParams();
int height = view.getHeight();
//注意这里的动画,直到1,而没有到0,也就是刚才所说的大致到0.
ValueAnimator va = ValueAnimator.ofFloat(height, 1f);
va.setDuration(300);
va.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
data.remove(position);
adapter.notifyDataSetChanged();
super.onAnimationEnd(animation);
}
});
va.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (Float) animation.getAnimatedValue();
layoutParams.height = (int) value;
view.requestLayout();
}
});


va.setTarget(view);
va.start();
}


public void powu(final View view) {


}


class myAdapter extends BaseAdapter {
private List<String> data;


public myAdapter(Context context, List<String> data) {
this.data = data;
}


@Override
public int getCount() {
return data.size();
}


@Override
public Object getItem(int position) {
return data.get(position);
}


@Override
public long getItemId(int position) {
return 0;
}


@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView textView = getTextView();
textView.setText(data.get(position));
textView.setTag(position);


if (showShadow && movedItemPosition == position) {
textView.setVisibility(View.GONE);
}
return textView;
}
}


public TextView getTextView() {
TextView text = new TextView(this);
text.setTextSize(30);
text.setTextColor(Color.BLACK);


return text;
}


}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值