Android 实现新闻端平拉动删除,拉下条新闻,上条新闻弹回特效
发布日期:2021-06-30 22:37:29 浏览次数:3 分类:技术文章

本文共 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方法

@Override

public 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 QuickAdapter
mAdapter = 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 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:jQuery 阻止表单重复提交
下一篇:OC中的私有方法

发表评论

最新留言

能坚持,总会有不一样的收获!
[***.219.124.196]2024年04月17日 01时59分28秒