Android 实现ListView的滑动删除效果(转)

来源:互联网 发布:淘宝直播伴侣 编辑:程序博客网 时间:2024/06/06 01:41
<?xml version="1.0" encoding="utf-8"?>  <merge xmlns:android="http://schemas.android.com/apk/res/android"      android:layout_width="match_parent"      android:layout_height="match_parent" >        <LinearLayout          android:id="@+id/view_content"          android:layout_width="match_parent"          android:layout_height="match_parent"          android:orientation="horizontal" >      </LinearLayout>        <RelativeLayout          android:id="@+id/holder"          android:layout_width="120dp"          android:layout_height="match_parent"          android:clickable="true"          android:background="@drawable/holder_bg">            <TextView              android:id="@+id/delete"              android:layout_width="wrap_content"              android:layout_height="wrap_content"              android:drawableLeft="@drawable/del_icon_normal"              android:layout_centerInParent="true"              android:gravity="center"              android:textColor="@color/floralwhite"              android:text="删除" />      </RelativeLayout>    </merge>  

上述xml文件中,所有的view都会被放在view_content中,而holder是放置诸如删除按钮之类的东西,我们的SlideView会加载这个布局。

再看SlideView.java:

/*** SlideView 继承自LinearLayout*/public class SlideView extends LinearLayout {private static final String TAG = "SlideView";private Context mContext;// 用来放置所有view的容器private LinearLayout mViewContent;// 用来放置内置view的容器,比如删除 按钮private RelativeLayout mHolder;// 弹性滑动对象,提供弹性滑动效果private Scroller mScroller;// 滑动回调接口,用来向上层通知滑动事件private OnSlideListener mOnSlideListener;// 内置容器的宽度 单位:dpprivate int mHolderWidth = 120;// 分别记录上次滑动的坐标private int mLastX = 0;private int mLastY = 0;// 用来控制滑动角度,仅当角度a满足如下条件才进行滑动:tan a = deltaX / deltaY > 2private static final int TAN = 2;public interface OnSlideListener {// SlideView的三种状态:开始滑动,打开,关闭public static final int SLIDE_STATUS_OFF = 0;public static final int SLIDE_STATUS_START_SCROLL = 1;public static final int SLIDE_STATUS_ON = 2;/*** @param view* current SlideView* @param status* SLIDE_STATUS_ON, SLIDE_STATUS_OFF or* SLIDE_STATUS_START_SCROLL*/public void onSlide(View view, int status);}public SlideView(Context context) {super(context);initView();}public SlideView(Context context, AttributeSet attrs) {super(context, attrs);initView();}private void initView() {mContext = getContext();// 初始化弹性滑动对象mScroller = new Scroller(mContext);// 设置其方向为横向setOrientation(LinearLayout.HORIZONTAL);// 将slide_view_merge加载进来View.inflate(mContext, R.layout.slide_view_merge, this);mViewContent = (LinearLayout) findViewById(R.id.view_content);mHolderWidth = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mHolderWidth, getResources().getDisplayMetrics()));}// 设置按钮的内容,也可以设置图标啥的,我没写public void setButtonText(CharSequence text) {((TextView) findViewById(R.id.delete)).setText(text);}// 将view加入到ViewContent中public void setContentView(View view) {mViewContent.addView(view);}// 设置滑动回调public void setOnSlideListener(OnSlideListener onSlideListener) {mOnSlideListener = onSlideListener;}// 将当前状态置为关闭public void shrink() {if (getScrollX() != 0) {this.smoothScrollTo(00);}}// 根据MotionEvent来进行滑动,这个方法的作用相当于onTouchEvent// 如果你不需要处理滑动冲突,可以直接重命名,照样能正常工作public void onRequireTouchEvent(MotionEvent event) {int x = (int) event.getX();int y = (int) event.getY();int scrollX = getScrollX();Log.d(TAG, "x=" + x + " y=" + y);switch (event.getAction()) {case MotionEvent.ACTION_DOWN: {if (!mScroller.isFinished()) {mScroller.abortAnimation();}if (mOnSlideListener != null) {mOnSlideListener.onSlide(this,OnSlideListener.SLIDE_STATUS_START_SCROLL);}break;}case MotionEvent.ACTION_MOVE: {int deltaX = x - mLastX;int deltaY = y - mLastY;if (Math.abs(deltaX) < Math.abs(deltaY) * TAN) {// 滑动不满足条件,不做横向滑动break;}// 计算滑动终点是否合法,防止滑动越界int newScrollX = scrollX - deltaX;if (deltaX != 0) {if (newScrollX < 0) {newScrollX = 0;} else if (newScrollX > mHolderWidth) {newScrollX = mHolderWidth;}this.scrollTo(newScrollX, 0);}break;}case MotionEvent.ACTION_UP: {int newScrollX = 0;// 这里做了下判断,当松开手的时候,会自动向两边滑动,具体向哪边滑,要看当前所处的位置if (scrollX - mHolderWidth * 0.75 > 0) {newScrollX = mHolderWidth;}// 慢慢滑向终点this.smoothScrollTo(newScrollX, 0);// 通知上层滑动事件if (mOnSlideListener != null) {mOnSlideListener.onSlide(this,newScrollX == 0 ? OnSlideListener.SLIDE_STATUS_OFF: OnSlideListener.SLIDE_STATUS_ON);}break;}default:break;}mLastX = x;mLastY = y;}private void smoothScrollTo(int destX, int destY) {// 缓慢滚动到指定位置int scrollX = getScrollX();int delta = destX - scrollX;// 以三倍时长滑向destX,效果就是慢慢滑动mScroller.startScroll(scrollX, 0, delta, 0, Math.abs(delta) * 3);invalidate();}@Overridepublic void computeScroll() {if (mScroller.computeScrollOffset()) {scrollTo(mScroller.getCurrX(), mScroller.getCurrY());postInvalidate();}}}

上述代码做了很详细的说明,这就是滑动控件的完整代码,大家要明白的是:你所添加的view都是加在SlideView的子View : view_content中的,而不是直接加在SlideView中,只有这样我们才方便做滑动效果。

接着看ListView的代码:核心就是下面这一个方法,将点击事件发送给SlideView处理。

@Override  public boolean onTouchEvent(MotionEvent event) {      switch (event.getAction()) {      case MotionEvent.ACTION_DOWN: {          int x = (intevent.getX();          int y = (intevent.getY();          //我们想知道当前点击了哪一行          int position = pointToPosition(x, y);          Log.e(TAG, "postion=" + position);          if (position != INVALID_POSITION) {              //得到当前点击行的数据从而取出当前行的item。              //可能有人怀疑,为什么要这么干?为什么不用getChildAt(position)?              //因为ListView会进行缓存,如果你不这么干,有些行的view你是得不到的。              MessageItem data = (MessageItem) getItemAtPosition(position);              mFocusedItemView = data.slideView;              Log.e(TAG, "FocusedItemView=" + mFocusedItemView);          }      }      default:          break;      }        //向当前点击的view发送滑动事件请求,其实就是向SlideView发请求      if (mFocusedItemView != null) {          mFocusedItemView.onRequireTouchEvent(event);      }        return super.onTouchEvent(event);  }  
最后看Activity的代码:
public class MainActivity extends Activity implements OnItemClickListener,          OnClickListenerOnSlideListener {        private static final String TAG = "MainActivity";        private ListViewCompat mListView;        private List<MessageItem> mMessageItems = new ArrayList<MainActivity.MessageItem>();        private SlideAdapter mSlideAdapter;        // 上次处于打开状态的SlideView      private SlideView mLastSlideViewWithStatusOn;        @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_main);          initView();      }        private void initView() {          mListView = (ListViewCompat) findViewById(R.id.list);            for (int i = 0; i < 20; i++) {              MessageItem item = new MessageItem();              if (i % 3 == 0) {                  item.iconRes = R.drawable.default_qq_avatar;                  item.title = "腾讯新闻";                  item.msg = "青岛爆炸满月:大量鱼虾死亡";                  item.time = "晚上18:18";              } else {                  item.iconRes = R.drawable.wechat_icon;                  item.title = "微信团队";                  item.msg = "欢迎你使用微信";                  item.time = "12月18日";              }              mMessageItems.add(item);          }          mSlideAdapter = new SlideAdapter();          mListView.setAdapter(mSlideAdapter);          mListView.setOnItemClickListener(this);      }        private class SlideAdapter extends BaseAdapter {            private LayoutInflater mInflater;            SlideAdapter() {              super();              mInflater = getLayoutInflater();          }            @Override          public int getCount() {              return mMessageItems.size();          }            @Override          public Object getItem(int position) {              return mMessageItems.get(position);          }            @Override          public long getItemId(int position) {              return position;          }            @Override          public View getView(int position, View convertView, ViewGroup parent) {              ViewHolder holder;              SlideView slideView = (SlideView) convertView;              if (slideView == null) {                  // 这里是我们的item                  View itemView = mInflater.inflate(R.layout.list_item, null);                    slideView = new SlideView(MainActivity.this);                  // 这里把item加入到slideView                  slideView.setContentView(itemView);                  // 下面是做一些数据缓存                  holder = new ViewHolder(slideView);                  slideView.setOnSlideListener(MainActivity.this);                  slideView.setTag(holder);              } else {                  holder = (ViewHolder) slideView.getTag();              }              MessageItem item = mMessageItems.get(position);              item.slideView = slideView;              item.slideView.shrink();                holder.icon.setImageResource(item.iconRes);              holder.title.setText(item.title);              holder.msg.setText(item.msg);              holder.time.setText(item.time);              holder.deleteHolder.setOnClickListener(MainActivity.this);                return slideView;          }        }        public class MessageItem {          public int iconRes;          public String title;          public String msg;          public String time;          public SlideView slideView;      }        private static class ViewHolder {          public ImageView icon;          public TextView title;          public TextView msg;          public TextView time;          public ViewGroup deleteHolder;            ViewHolder(View view) {              icon = (ImageView) view.findViewById(R.id.icon);              title = (TextView) view.findViewById(R.id.title);              msg = (TextView) view.findViewById(R.id.msg);              time = (TextView) view.findViewById(R.id.time);              deleteHolder = (ViewGroup) view.findViewById(R.id.holder);          }      }        @Override      public void onItemClick(AdapterView<?> parent, View view, int position,              long id) {          // 这里处理ListItem的点击事件          Log.e(TAG, "onItemClick position=" + position);      }        @Override      public void onSlide(View view, int status) {          // 如果当前存在已经打开的SlideView,那么将其关闭          if (mLastSlideViewWithStatusOn != null                  && mLastSlideViewWithStatusOn != view) {              mLastSlideViewWithStatusOn.shrink();          }          // 记录本次处于打开状态的view          if (status == SLIDE_STATUS_ON) {              mLastSlideViewWithStatusOn = (SlideView) view;          }      }        @Override      public void onClick(View v) {          // 这里处理删除按钮的点击事件,可以删除对话          if (v.getId() == R.id.holder) {              int position = mListView.getPositionForView(v);              if (position != ListView.INVALID_POSITION) {                  mMessageItems.remove(position);                  mSlideAdapter.notifyDataSetChanged();              }              Log.e(TAG, "onClick v=" + v);          }      }  }  

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 老婆在外省工作不回到我身边怎么办 知道扣扣号怎样盗取他的密码怎么办 喜欢养猫又怕猫破坏家里怎么办 约她她每次都找借口怎么办? 遇到总是找借口不还钱的人怎么办 装修好了业主找借口不给钱怎么办 荒野行动手机换了帐号登不上怎么办 换新手机后微信头像都没有了怎么办 苹果系统维护换不了微信头像怎么办 系统通知栏不显示qq图标怎么办 快递号码写错了而且发货了怎么办 包裹遗忘在郑州东站安检口了怎么办 锁书包的锁头钥匙全掉了怎么办 平板电脑恢复出厂设置变英语怎么办 给国外银行汇款账号写错账号怎么办 顺丰快递暴力运输产品坏了怎么办 亚航订机票名字少写一个字母怎么办 如果淘宝付款七天内不发货怎么办 浪琴手表调了一下日期不走了怎么办 收件人号码写错快递柜已签收怎么办 医院名字写错了怎么办保险报销 电脑在使用中出现了英文字慕怎么办 下雨天了怎么办我好想你是什么歌 安卓手机不支持微信运动怎么办 装系统时无法跳过密匙怎么办 在msdn里下的系统没有网怎么办 w7电脑更新后系统没法激活怎么办 手机使用加速器后网速变卡怎么办 奥特曼ol分解了迪迦石像怎么办 左右棋牌游戏兑换总说系统护怎么办 四季海棠扦插以后黄叶卷叶怎么办 竹节海棠浇水多了叶子蔫了怎么办 社保停缴了里面的钱怎么办 王者荣耀英雄释放技能有延迟怎么办 买的桑拿木板颜色太深了怎么办 万一填写了奔跑吧诈骗信息该怎么办 深圳限行时段堵在路上怎么办 开车堵在路上到了限行时间怎么办 兄妹之间都不想照顾母亲我该怎么办 小孩扁体发炎睡觉呼吸声沉重怎么办 客所思pk3老驱动有杂音怎么办