本文共 10199 字,大约阅读时间需要 33 分钟。
一、概述:
1、目前一般的手机下拉信息栏时,会显示很多自己不想看到的内能,但我们又不想去触发它,这些厂商就实现了平拉动的时候可以把这些信息删除,就不会显示在顶部的信息里了!
2、但我们今天要实现的效果与这个差不多,但必须手动点击删除,如图:3、那我们如何实现呢?仔细观看图片,其实是使用了两个图层,上面是个拖拽图层,下面是个按钮图层,把上面一层移动到某个位置时,显示下面的按钮,然后点击按钮,隐藏上面的图层
那既然讲到了侧拉,当然会想到现在最流行的工具类ViewDragHelper 那么我们先实现基本的功能。。。。。。。。。。。二、实现基本功能:
1、创建自定义的View
public class SwipeLayout extends FrameLayout { public SwipeLayout(Context context) { super(context, null); } public SwipeLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public SwipeLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); }}
2、创建布局
3、创建主页
public class SwipeActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_swipe); }}
这些基础框架搭建好后,我们得开始写ViewDragHelper。。。。。。。。。。。
三、ViewDragHelper基本写法
1、第一步:在构造方法里初始化
mHelper = ViewDragHelper.create(this, 1.0f, mCallback);private Callback mCallback = new Callback() { @Override public boolean tryCaptureView(View arg0, int arg1) { // TODO Auto-generated method stub return false; }};
2、第二步:复写onInterceptTouchEvent
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { return mHelper.shouldInterceptTouchEvent(ev); }
3、第三步:复写onTouchEvent
@Override public boolean onTouchEvent(MotionEvent event) { try { mHelper.processTouchEvent(event); } catch (Exception e) { e.printStackTrace(); } return true; }
四、实现基本的拖动效果
1、我们现在写个有两层的布局文件,上层是内容,下面一层是按钮
2、在SwipeLayout里的回调函数里复写clampViewPositionHorizontal方法
@Overridepublic int clampViewPositionHorizontal(View child, int left, int dx) { return left;}
3)在onFinishInflate方法里获得子控件
private View mBackView;private View mFrontView;/** * 当xml被填充完成后调用 */ @Override protected void onFinishInflate() { super.onFinishInflate(); mBackView = getChildAt(0); mFrontView = getChildAt(1); }
4、在onLayout里来设置子控件的位置
@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); //布局子控件 layoutChild(false);}/** * 根据控件是否关闭来布 * @param isOpen */private void layoutChild(boolean isOpen) { Rect frontRect = computeFrontViewRect(isOpen); mFrontView.layout(frontRect.left, frontRect.top, frontRect.right, frontRect.bottom); Rect backRect = computeBackViewRect(frontRect); mBackView.layout(backRect.left, backRect.top, backRect.right, backRect.bottom); //绘制完后置于前面 bringChildToFront(mFrontView);}private Rect computeBackViewRect(Rect frontRect) { int left = frontRect.right; return new Rect(left, frontRect.top, left + mRange, frontRect.bottom);}private Rect computeFrontViewRect(boolean isOpen) { int left = 0; int top = 0; int right = left + mWidth; int bottom = top + mHeight; if (isOpen) { left = -mRange; } return new Rect(left, top, right, bottom);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mWidth = mFrontView.getMeasuredWidth(); mHeight = mFrontView.getMeasuredHeight(); mRange = mBackView.getMeasuredWidth();}
5.如何实现上层控件拖动下层也跟着拖动,在回调函数里复写onViewPositionChanged方法
@Overridepublic void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { if (changedView == mFrontView) { //让后面的view跟着前面的view相同的距离 mBackView.offsetLeftAndRight(dx); }else if (changedView == mBackView) { mFrontView.offsetLeftAndRight(dx); } if (dx > mRange) { dx = mRange; }else if (dx < 0) { dx = 0; } invalidate();}
6、限制移动的范围
/** * 在这里修正 */@Overridepublic int clampViewPositionHorizontal(View child, int left, int dx) { if (child == mFrontView) { if (left < -mRange) { left = -mRange; } else if (left > 0) { left = 0; } } else if (child == mBackView) { if (left < mWidth - mRange) { left = mWidth - mRange; } else if (left > mWidth) { left = mWidth; } } return left;}
7、在松手的时候,实现如果>mrang/2时就open,否则就close
@Overridepublic void onViewReleased(View releasedChild, float xvel, float yvel) { super.onViewReleased(releasedChild, xvel, yvel); if (xvel == 0 && mFrontView.getLeft() < -mRange / 2.0f) { open(); } else if (xvel < 0) { open(); } else { close(); }}
8、但这样是不是太单调了,没有动画效果,如果你的boss发现,岂不要被叼,那我们就加上一个平滑的效果
public void open(boolean isSmooth){ int finalLeft = -mRange; if (isSmooth) { //开始动画 if (mHelper.smoothSlideViewTo(mFrontView, finalLeft, 0)) { //没到达重绘 ViewCompat.postInvalidateOnAnimation(this); } }else { open(); } } protected void open() { layoutChild(true); } protected void close() { layoutChild(false); } public void close(boolean isSmooth){ int finalLeft = 0; if (isSmooth) { //开始动画 if (mHelper.smoothSlideViewTo(mFrontView, finalLeft, 0)) { //没到达重绘 ViewCompat.postInvalidateOnAnimation(this); } }else { close(); } } /** * 实现持续动画 */ @Override public void computeScroll() { super.computeScroll(); if (mHelper.continueSettling(true)) { ViewCompat.postInvalidateOnAnimation(this); } }
五、添加状态与监听
1.添加状态
private Status msStatus = Status.CLOSE;public static enum Status { CLOSE, OPEN, DRAGING }
2.添加监听
public interface onSwipeListener{ void onClose(SwipeLayout layout); void onOpen(SwipeLayout layout); void onDraging(SwipeLayout layout); void onStartOpen(SwipeLayout layout);//表示准备打开时,其它的条目开始关闭 void onStartClose(SwipeLayout layout);}private onSwipeListener mListener;public void setOnSwipeListener(onSwipeListener listener){ this.mListener = listener;}
3.在什时候调用监听呢?当然是在位置变化的时候,所以我们在onViewPositionChanged方法里插入方法
dispatchSwipeEvent();protected void dispatchSwipeEvent() { mListener.onDraging(this); // 记录上一次的状态 Status preStatus = mStatus; // 更新当前状态 mStatus = updateStatus(); // 判断 if (mStatus != preStatus && mListener != null) { if (mStatus == Status.CLOSE) { mListener.onClose(this); } else if (mStatus == Status.OPEN) { mListener.onOpen(this); } else if (mStatus == Status.DRAGING) { //如果上次是关闭状态,就表示准备打开 if (preStatus == Status.CLOSE) { mListener.onStartOpen(this); }else if (preStatus == Status.OPEN) { mListener.onStartClose(this); } } }}/** * 更新状态 * * @return */private Status updateStatus() { int left = mFrontView.getLeft(); if (left == 0) { return Status.CLOSE; } else if (left == -mRange) { return Status.OPEN; } return Status.DRAGING;}
六、把上面的item添加到listview
1.创建布局
2、把主页布局设置成上面的布局
setContentView(R.layout.activity_swipe_list);
3、把原来的布局改成item_list布局
4、在主页里初始化数据private void initDatas() { mOpenLayouts = new HashMap(); mDatas = new ArrayList (); for (int i = 0; i < Cheeses.NAMES.length; i++) { mDatas.add(Cheeses.NAMES[i]); } }
5、创建Adapter
private QuickAdaptermAdapter = new QuickAdapter (this, R.layout.item_list, mDatas) { private SwipeLayout mSwipeLayout; @Override protected void convert(final BaseAdapterHelper helper, final String item) { //设置数据 helper.setText(R.id.tv_name, item); notifyDataSetChanged(); final int position = helper.getPosition(); Logger.i("tag", "position ==" + position); View call = helper.getView(R.id.tv_call); //删除 View del = helper.getView(R.id.tv_del); del.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { remove(item); } }); View convertView = helper.getView(); //设置监听打开一个条目,关闭其它条目 if (convertView instanceof SwipeLayout) { mSwipeLayout = (SwipeLayout) convertView; mSwipeLayout.setOnSwipeListener(new onSwipeListener() { @Override public void onStartOpen(SwipeLayout layout) { Logger.d(TAG, "onStartOpen"); for(Integer key : mOpenLayouts.keySet()){ SwipeLayout swipeLayout = mOpenLayouts.get(key); swipeLayout.close(true); } mOpenLayouts.clear(); } @Override public void onStartClose(SwipeLayout layout) { Logger.d(TAG, "onStartClose"); } @Override public void onOpen(SwipeLayout layout) { Logger.d(TAG, "onOpen"); //添加到集合 mOpenLayouts.put(position, layout); } @Override public void onDraging(SwipeLayout layout) { Logger.d(TAG, "onDraging"); } @Override public void onClose(SwipeLayout layout) { Logger.d(TAG, "onClose"); mOpenLayouts.remove(position); } }); } } };
6、把adapter设置到listview里,好了,这样就大功搞成了
七、源码下载:
链接: 密码:u5ys
———————————————————————
有需求者请加qq:136137465,非诚勿扰 (java 架构师全套教程,共760G, 让你从零到架构师,每月轻松拿3万) 01.高级架构师四十二个阶段高 02.Java高级系统培训架构课程148课时 03.Java高级互联网架构师课程 04.Java互联网架构Netty、Nio、Mina等-视频教程 05.Java高级架构设计2016整理-视频教程 06.架构师基础、高级片 07.Java架构师必修linux运维系列课程 08.Java高级系统培训架构课程116课时 (送:hadoop系列教程,java设计模式与数据结构, Spring Cloud微服务, SpringBoot入门) ——————————————————————–转载地址:https://lovoo.blog.csdn.net/article/details/51534022 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!