可拖動和刪除動畫的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;
}


}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章