Android开发之高仿QQ消息侧拉删除
QQ消息的侧滑删除效果之炫酷,想必大家都见过吧,本人作为一名安卓开发人员,遇到如此炫酷的效果,怎能不研究一番呢,现本人已实现其基本功能,现将代码贴出,望各位大神批评指正,不喜勿喷,灰常感谢O(∩_∩)O哈哈~
下面我们废话少说,直接上代码啦!
核心代码:
MainActivity:
package com.hxht.testlvwithdragmessageitem; import android.app.Activity; import android.os.Bundle; import android.widget.ListView; import com.hxht.testlvwithdragmessageitem.adapter.MyAdapter; import com.hxht.testlvwithdragmessageitem.customview.DragMessageView; import java.util.ArrayList; import java.util.List; public class MainActivity extends Activity { private ListView lv; private String[] names = new String[]{ "宋江", "卢俊义", "吴用", "公孙胜", "关胜", "林冲", "秦明", "呼延灼", "花荣", "柴进", "李应", "朱仝", "鲁智深", "武松", "董平", "张清", "杨志", "徐宁", "索超", "戴宗", "刘唐", "李逵", "史进", "穆弘", "雷横", "李俊", "阮小二", "张横", "阮小五", "张顺", "阮小七", "杨雄", "石秀", "解珍", "解宝 ", "燕青", "朱武", "黄信", "孙立", "宣赞", "郝思文", "韩滔", "彭玘", "单廷圭", "魏定国", "萧让", "裴宣", "欧鹏", "邓飞", "燕顺", "杨林", "凌振", "蒋敬", "吕方", "郭盛", "安道全", "皇甫端", "王英", "扈三娘", "鲍旭", "樊瑞", "孔明", "孔亮", "项充", "李衮", "金大坚", "马麟", "童威", "童猛", "孟康", "侯健", "陈达", "杨春", "郑天寿", "陶宗旺", "宋清", "乐和", "龚旺", "丁得孙", "穆春", "曹正", "宋万", "杜迁", "薛永", "李忠", "周通", "汤隆", "杜兴", "邹渊", "邹润", "朱贵", "朱富", "施恩", "蔡福", "蔡庆", "李立", "李云", "焦挺", "石勇", "孙新", "顾大嫂", "孙二娘", "王定六", "郁保四", "白胜", "时迁", "段景住" }; private List<String> list; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_lv); initView(); initData(); } private void initView() { lv = (ListView) findViewById(R.id.lv); list = new ArrayList<>(); list.clear(); for (int i = 0; i < names.length; i++) { list.add(names[i]); } } private void initData() { MyAdapter adapter = new MyAdapter(list, MainActivity.this); lv.setAdapter(adapter); } }
Utils:
package com.hxht.testlvwithdragmessageitem.utils; import android.app.Activity; import android.widget.Toast; public class Utils { public static void showSafeToast(final Activity activity, final String msg) { if ("main".equals(Thread.currentThread().getName())) { Toast.makeText(activity, msg, Toast.LENGTH_SHORT).show(); } else { activity.runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(activity, msg, Toast.LENGTH_SHORT).show(); } }); } } }
package com.hxht.testlvwithdragmessageitem.customview; import android.content.Context; import android.graphics.Rect; import android.support.v4.view.ViewCompat; import android.support.v4.widget.ViewDragHelper; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; public class DragMessageView extends FrameLayout { private ViewDragHelper mViewDragHelper; private ViewGroup backView; private ViewGroup frontView; private int mWidth; private int mHeight; private int mRange; private static enum Status { CLOSE, OPEN, DRAGING } public interface OnDragChangeListener { void onOpen(); void onClose(); void onDraging(); } private OnDragChangeListener mOnDragChangeListener; public OnDragChangeListener getmOnDragChangeListener() { return mOnDragChangeListener; } public void setmOnDragChangeListener(OnDragChangeListener mOnDragChangeListener) { this.mOnDragChangeListener = mOnDragChangeListener; } private Status status = Status.CLOSE; private ViewDragHelper.Callback mCallback = new ViewDragHelper.Callback() { //第三步:处理监听 @Override public boolean tryCaptureView(View child, int pointerId) { return true; } @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { super.onViewPositionChanged(changedView, left, top, dx, dy); if (changedView == frontView) { backView.offsetLeftAndRight(dx); } else if (changedView == backView) { frontView.offsetLeftAndRight(dx); } dispatchDragEvents(); invalidate(); } @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { super.onViewReleased(releasedChild, xvel, yvel); if (xvel < 0) { open(); } else if (xvel == 0 && frontView.getLeft() < -(mRange / 2)) { open(); } else { close(); } } @Override public int getViewHorizontalDragRange(View child) { return mRange; } @Override public int clampViewPositionHorizontal(View child, int left, int dx) { if (child == frontView) { left = fixLeft(left); } if (child == backView) { left = computeLeft(left); } return left; } }; private void dispatchDragEvents() { Status lastStatus = status; status = updateStatus(); if (lastStatus != status) { if (mOnDragChangeListener != null) { if (status == Status.CLOSE) { mOnDragChangeListener.onClose(); } else if (status == Status.OPEN) { mOnDragChangeListener.onOpen(); } else { mOnDragChangeListener.onDraging(); } } } } private Status updateStatus() { int left = frontView.getLeft(); if (left == 0) { return Status.CLOSE; } else if (left == -mRange) { return Status.OPEN; } else { return Status.DRAGING; } } @Override public void computeScroll() { super.computeScroll(); if (mViewDragHelper.continueSettling(true)) { ViewCompat.postInvalidateOnAnimation(this); } } public void close() { close(true); } private void close(boolean isSmooth) { if (isSmooth) { if (mViewDragHelper.smoothSlideViewTo(frontView, 0, 0)) { ViewCompat.postInvalidateOnAnimation(this); } } else { layoutViews(false); } } private void open() { open(true); } private void open(boolean isSmooth) { if (isSmooth) { if (mViewDragHelper.smoothSlideViewTo(frontView, -mRange, 0)) { ViewCompat.postInvalidateOnAnimation(this); } } else { layoutViews(true); } } private int computeLeft(int left) { if (left < mWidth - mRange) { return mWidth - mRange; } else if (left > mWidth) { return mWidth; } else { return left; } } private int fixLeft(int left) { if (left > 0) { return 0; } else if (left < -mRange) { return -mRange; } else { return left; } } public DragMessageView(Context context) { this(context, null); } public DragMessageView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public DragMessageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); //第一步:初始化ViewDragHelper的实例对象 mViewDragHelper = ViewDragHelper.create(this, mCallback); } //第二步:托管触摸事件 @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return mViewDragHelper.shouldInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { try { mViewDragHelper.processTouchEvent(event); } catch (Exception e) { e.printStackTrace(); } return true; } @Override protected void onFinishInflate() { super.onFinishInflate(); if (getChildCount() < 2) { throw new IllegalArgumentException("This ViewGroup must have two childern at least!"); } if (!(getChildAt(0) instanceof ViewGroup) || !(getChildAt(1) instanceof ViewGroup)) { throw new IllegalArgumentException("The children must be instanceof ViewGroup!"); } backView = (ViewGroup) getChildAt(0); frontView = (ViewGroup) getChildAt(1); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mWidth = getMeasuredWidth(); mHeight = getMeasuredHeight(); mRange = backView.getMeasuredWidth(); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); layoutViews(false); } /** * 初始化控件的位置 * * @param isOpen */ private void layoutViews(boolean isOpen) { Rect backRect = layoutBackView(isOpen); backView.layout(backRect.left, backRect.top, backRect.right, backRect.bottom); Rect frontRect = layoutFrontView(isOpen); frontView.layout(frontRect.left, frontRect.top, frontRect.right, frontRect.bottom); } private Rect layoutBackView(boolean isOpen) { int newLeft = mWidth; if (isOpen) { newLeft = mWidth - mRange; } return new Rect(newLeft, 0, newLeft + mWidth, mHeight); } private Rect layoutFrontView(boolean isOpen) { int newLeft = 0; if (isOpen) { newLeft = -mRange; } return new Rect(newLeft, 0, newLeft + mWidth, mHeight); } }
package com.hxht.testlvwithdragmessageitem.adapter; import android.content.Context; import android.view.View; import android.view.ViewGroup; import android.widget.Adapter; import android.widget.BaseAdapter; import android.widget.TextView; import com.hxht.testlvwithdragmessageitem.R; import com.hxht.testlvwithdragmessageitem.customview.DragMessageView; import java.util.HashSet; import java.util.List; public class MyAdapter extends BaseAdapter { private List<String> list; private Context context; private HashSet<DragMessageView> set = new HashSet<>(); public MyAdapter(List<String> list, Context context) { this.list = list; this.context = context; } @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(final int position, View convertView, ViewGroup parent) { View view = null; if (convertView == null) { view = View.inflate(context, R.layout.activity_main, null); } else { view = convertView; } final DragMessageView dragMessageView = (DragMessageView) view; dragMessageView.setmOnDragChangeListener(new DragMessageView.OnDragChangeListener() { @Override public void onOpen() { set.add(dragMessageView); } @Override public void onClose() { set.remove(dragMessageView); } @Override public void onDraging() { for (DragMessageView dragview : set) { dragview.close(); } } }); ViewHolder holder = ViewHolder.getHolder(view); holder.tv.setText(list.get(position)); holder.tv_tofirst.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //Toast.makeText(context, "当前条目" + position + "----置顶", Toast.LENGTH_SHORT).show(); String str = list.get(position); list.remove(str) ; list.add(0, str); MyAdapter.this.notifyDataSetChanged(); } }); holder.tv_todelete.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //Toast.makeText(context, "当前条目" + position + "----删除", Toast.LENGTH_SHORT).show(); list.remove(position); MyAdapter.this.notifyDataSetChanged(); } }); return view; } private static class ViewHolder { TextView tv; TextView tv_tofirst; TextView tv_todelete; public ViewHolder(TextView tv, TextView tv_tofirst, TextView tv_todelete) { this.tv = tv; this.tv_tofirst = tv_tofirst; this.tv_todelete = tv_todelete; } public static ViewHolder getHolder(View view) { Object tag = view.getTag(); if (tag != null) { return ((ViewHolder) tag); } else { return new ViewHolder(( (TextView) view.findViewById(R.id.tv)), ((TextView) view.findViewById(R.id.tv_tofirst)), ((TextView) view.findViewById(R.id.tv_todelete))); } } } }
布局文件:
activity_main.xml
<com.hxht.testlvwithdragmessageitem.customview.DragMessageView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/dragmessageview" android:layout_width="match_parent" android:splitMotionEvents="false" android:layout_height="wrap_content" tools:context=".MainActivity"> <LinearLayout android:id="@+id/backview" android:layout_width="160dip" android:layout_height="60dip" android:orientation="horizontal" android:weightSum="2"> <TextView android:id="@+id/tv_tofirst" android:layout_width="80dip" android:layout_height="match_parent" android:layout_gravity="center" android:background="#999999" android:gravity="center" android:text="置顶" android:textColor="#FFFFFF" android:textSize="24dp" /> <TextView android:id="@+id/tv_todelete" android:layout_width="80dip" android:layout_height="match_parent" android:layout_gravity="center" android:background="#ff0000" android:gravity="center" android:text="删除" android:textColor="#ffffff" android:textSize="24dp" /> </LinearLayout> <LinearLayout android:id="@+id/frontview" android:layout_width="match_parent" android:layout_height="60dip" android:background="#A3AF91" android:orientation="horizontal"> <de.hdodenhof.circleimageview.CircleImageView xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/profile_image" android:layout_width="45dip" android:layout_height="45dip" android:layout_gravity="center_vertical" android:layout_marginLeft="45dip" android:src="@mipmap/iv_bg" app:border_color="#FF000000" app:border_width="2dp" /> <TextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginLeft="30dip" android:gravity="center_vertical" android:text="宋江" android:textColor="#ffffff" android:textSize="26dp" /> </LinearLayout> </com.hxht.testlvwithdragmessageitem.customview.DragMessageView>
activity_lv.xml
<?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="match_parent" android:splitMotionEvents="false" android:orientation="vertical"> <ListView android:id="@+id/lv" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
效果图如下:
代码已贴出,正所谓取之于社会,回报于社会,还望各位大神批评指正,多多指教,不喜勿喷,灰常感谢 O(∩_∩)O哈哈~