android高仿qq源码,Android高仿QQ6.0侧滑删除实例代码

推荐阅读:

先给大家分享一下,侧滑删除,布局也就是前面一个item,然后有两个隐藏的按钮(TextView也可以),然后我们可以向左侧滑动,然后显示出来,然后对delete(删除键)实现监听,就可以了哈。好了那就来看看代码怎么实现的吧。

首先和之前一样

自定义View,初始化ViewDragHelper:

package com.example.removesidepull;

import android.content.Context;

import android.support.v4.widget.ViewDragHelper;

import android.util.AttributeSet;

import android.view.MotionEvent;

import android.view.View;

import android.widget.FrameLayout;

/**

* Created by 若兰 on 2016/2/2.

* 一个懂得了编程乐趣的小白,希望自己

* 能够在这个道路上走的很远,也希望自己学习到的

* 知识可以帮助更多的人,分享就是学习的一种乐趣

* QQ:1069584784

* csdn:http://blog.csdn.net/wuyinlei

*/

public class SwipeLayout extends FrameLayout {

private ViewDragHelper mDragHelper;

public SwipeLayout(Context context) {

this(context, null);

}

public SwipeLayout(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

public SwipeLayout(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

//第一步 初始化ViewDragHelper

mDragHelper = ViewDragHelper.create(this, mCallback);

}

ViewDragHelper.Callback mCallback = new ViewDragHelper.Callback() {

@Override

public boolean tryCaptureView(View child, int pointerId) {

//返回true

return true;

}

};

}

然后我们就要去处理拦截事件也就是重写一些onInterceptTouchEvent和onTouchEvent方法,默认是不拦截的:

/**

* 传递触摸事件

*

* @param ev

* @return

*/

@Override

public boolean onInterceptTouchEvent(MotionEvent ev) {

//交给ViewDragHelper判断是否去拦截事件

return mDragHelper.shouldInterceptTouchEvent(ev);

}

@Override

public boolean onTouchEvent(MotionEvent event) {

try {

mDragHelper.processTouchEvent(event);

} catch (Exception e) {

e.printStackTrace();

}

//返回true,这里表示去拦截事件

return true;

}

然后我们去重写一下ViewDragHelper里面的clampViewPositionHorizontal方法:

@Override

public int clampViewPositionHorizontal(View child, int left, int dx) {

return left;

}

好了这个时候,就已经可以实现滑动了,我们先来看下结果:

d0629354c08f0da4859f42528c008a92.gif

这里我们可以看到,已经可以滑动了,好了接下来的就是要处理滑动事件,去放置到正确的地方(call me 和删除刚开始不能见,还有只能左滑显示,右滑隐藏)。

好了,我们先获取两个View吧:

/**

* 当xml填充完毕的时候

*/

@Override

protected void onFinishInflate() {

super.onFinishInflate();

/**

* 后view

*/

mBackView = getChildAt(0);

/**

* 前view

*/

mFrontView = getChildAt(1);

}

获取想要的宽和高:

/**

* 在这里获取宽和高

*

* @param w

* @param h

* @param oldw

* @param oldh

*/

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

/**

* 高度

*/

mHeight = mFrontView.getMeasuredHeight();

/**

* 宽度

*/

mWidth = mFrontView.getMeasuredWidth();

/**

* 移动距离

*/

mRange = mBackView.getMeasuredWidth();

}

摆放这两个view的位置:

/**

* 摆放位置

* @param changed

* @param left

* @param top

* @param right

* @param bottom

*/

@Override

protected void onLayout(boolean changed, int left, int top, int right, int bottom) {

super.onLayout(changed, left, top, right, bottom);

layoutContent(false);

}

private void layoutContent(boolean isOpen) {

//摆放前view

Rect frontRect = computeFrontViewRect(isOpen);

mFrontView.layout(frontRect.left, frontRect.top, frontRect.right, frontRect.bottom);

//摆放后view

Rect backRect = computeBackViewRect(frontRect);

mBackView.layout(backRect.left,backRect.top,backRect.right,backRect.bottom);

//前置前view

bringChildToFront(mFrontView);

}

/**

* 我们可以把前view相当于一个矩形

*

* @param frontRect

* @return

*/

private Rect computeBackViewRect(Rect frontRect) {

int left = frontRect.right;

return new Rect(left, 0, left + mRange, 0 + mHeight);

}

private Rect computeFrontViewRect(boolean isOpen) {

int left = 0;

if (isOpen) {

left = -mRange;

}

return new Rect(left, 0, left + mWidth, 0 + mHeight);

}

当然这个实现,只是可以拖拽了前view,因为我们没有把改变的dx传递下去,好了来实现拖拽前view的时候,后view也跟着出来(ViewDragHelper里面的方法):

/**

* 当view位置改变的时候

* @param changedView 改变的view

* @param left

* @param top

* @param dx x轴偏移量

* @param dy

*/

@Override

public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {

super.onViewPositionChanged(changedView, left, top, dx, dy);

//传递事件,如果是拖拽的前view,

if (changedView == mFrontView){

//Offset this view's horizontal location by the specified amount of pixels.

//也就是说我的我的前view左滑了dx,那么我的后view也是左滑dx,右滑同理

mBackView.offsetLeftAndRight(dx);

} else if (changedView == mBackView){

//拖拽的是后view的话,前View的处理方式一样

mFrontView.offsetLeftAndRight(dx);

}

//兼容老版本

invalidate();

}

好了这个时候我们来看下效果:

95aa8b34b1206802e1fa4a220018bf48.gif

是不是发现了问题,就是我的前view想要的结果是不能右滑的(只允许左滑和返回),那么接下来就实现这个想要的结果吧。以下的代码是在clampViewPositionHorizontal()方法里面:

//在这里处理放置的逻辑拖拽的前view

if (child == mFrontView) {

if (left > 0) {

return 0;

} else if (left < -mRange) {

return -mRange;

}

}//拖拽的后view

else if (child == mBackView) {

if (left > mWidth) {

return mWidth;

} else if (left < mWidth - mRange) {

return mWidth - mRange;

}

}

看下效果图:

6945ffc869abf5c6e1ef6b4804a0b8e0.gif

好了,这个时候已经基本实现了,接下来实现以下滑动的距离和速度【判断是否打开和关闭:

/**

* 拖拽的view释放的时候

*

* @param releasedChild

* @param xvel

* @param yvel

*/

@Override

public void onViewReleased(View releasedChild, float xvel, float yvel) {

if (xvel == 0 && mFrontView.getLeft() < -mRange / 2.0f) {

open();

} else if (xvel < 0) {

open();

} else {

close();

}

}

/**

* 关闭

*/

public void close() {

Utils.showToast(getContext(), "close");

layoutContent(false);

}

//打开

public void open() {

//Utils.showToast(getContext(), "open");

layoutContent(true);

}

好了,接下来实现以下平滑的关闭和打开:

public void close() {

close(true);

}

/**

* 关闭

*

* @param isSmooth

*/

public void close(boolean isSmooth) {

int finalLeft = 0;

if (isSmooth) {

//开始动画 如果返回true表示没有完成动画

if (mDragHelper.smoothSlideViewTo(mFrontView, finalLeft, 0)) {

ViewCompat.postInvalidateOnAnimation(this);

}

} else {

layoutContent(false);

}

}

public void open() {

open(true);

}

/**

* 打开

*

* @param isSmooth

*/

public void open(boolean isSmooth) {

int finalLeft = -mRange;

if (isSmooth) {

//开始动画

if (mDragHelper.smoothSlideViewTo(mFrontView, finalLeft, 0)) {

ViewCompat.postInvalidateOnAnimation(this);

}

} else {

layoutContent(true);

}

}

/**

* 持续动画

*/

@Override

public void computeScroll() {

super.computeScroll();

//这个是固定的

if (mDragHelper.continueSettling(true)) {

ViewCompat.postInvalidateOnAnimation(this);

}

}

我们看下最终的效果吧:

6b936544c1fdc077213f33aa72ec5161.gif

好了,在这里我们加上一些回调,以方便外部使用的时候可以回调:

/**

* 默认状态是关闭

*/

private Status status = Status.Close;

private OnSwipeLayoutListener swipeLayoutListener;

public Status getStatus() {

return status;

}

public void setStatus(Status status) {

this.status = status;

}

public OnSwipeLayoutListener getSwipeLayoutListener() {

return swipeLayoutListener;

}

public void setSwipeLayoutListener(OnSwipeLayoutListener swipeLayoutListener) {

this.swipeLayoutListener = swipeLayoutListener;

}

/**

* 定义三种状态

*/

public enum Status {

Close, Open, Draging

}

/**

* 定义回调接口 这个在我们

*/

public interface OnSwipeLayoutListener {

/**

* 关闭

*

* @param mSwipeLayout

*/

void onClose(SwipeLayout mSwipeLayout);

/**

* 打开

*

* @param mSwipeLayout

*/

void onOpen(SwipeLayout mSwipeLayout);

/**

* 绘制

*

* @param mSwipeLayout

*/

void onDraging(SwipeLayout mSwipeLayout);

/**

* 要去关闭

*/

void onStartClose(SwipeLayout mSwipeLayout);

/**

* 要去开启

*/

void onStartOpen(SwipeLayout mSwipeLayout);

}

dispatchSwipeEvent()方法(在onViewPositionChanged()方法中调用)

protected void dispatchSwipeEvent() {

//判断是否为空

if (swipeLayoutListener != null) {

swipeLayoutListener.onDraging(this);

}

// 记录上一次的状态

Status preStatus = status;

// 更新当前状态

status = updateStatus();

if (preStatus != status && swipeLayoutListener != null) {

if (status == Status.Close) {

swipeLayoutListener.onClose(this);

} else if (status == Status.Open) {

swipeLayoutListener.onOpen(this);

} else if (status == Status.Draging) {

if (preStatus == Status.Close) {

swipeLayoutListener.onStartOpen(this);

} else if (preStatus == Status.Open) {

swipeLayoutListener.onStartClose(this);

}

}

}

}

updateStatus()方法:

/**

* 更新状态

*

* @return

*/

private Status updateStatus() {

//得到前view的左边位置

int left = mFrontView.getLeft();

if (left == 0) {

//如果位置是0,就是关闭状态

return Status.Close;

} else if (left == -mRange) {

//如果左侧边距是后view的宽度的负值,状态为开

return Status.Open;

}

//其他状态就是拖拽

return Status.Draging;

}

c2f36c7f4f4dbd34a8b0447254e81f05.gif

好了,事件基本上已经实现完毕了,这个侧拉删除的我会更新至我的项目中,同时希望Android高仿QQ6.0侧滑删除实例代码对大家有所帮助。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值