Android自定义SwipeLayout仿QQ侧滑条目
时间:2018-08-17
这篇文章主要为大家详细介绍了Android自定义SwipeLayout仿QQ侧滑条目,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
Android自定义SwipeLayout仿QQ侧滑条目,供大家参考,具体内容如下
先看动图
看布局文件
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="www.weshared.qqcehua.MainActivity"> <include layout="@layout/swipelayout" /> </RelativeLayout>
swipelayout.xml
<?xml version="1.0" encoding="utf-8"?> <www.weshared.qqcehua.SwipeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/swipelayout" android:layout_width="match_parent" android:layout_height="72dp"> <!--0 左边后布局--> <TextView android:id="@+id/back_left_tv_mark" android:layout_width="84dp" android:layout_height="match_parent" android:background="@android:color/holo_blue_dark" android:gravity="center" android:text="Mark" android:textColor="@android:color/white" android:textSize="20sp" /> <!--1 右边后布局--> <LinearLayout android:id="@+id/back_right_ll" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="right" android:orientation="horizontal"> <TextView android:id="@+id/back_right_tv_call" android:layout_width="84dp" android:layout_height="match_parent" android:background="@android:color/holo_orange_dark" android:gravity="center" android:text="Call" android:textColor="@android:color/white" android:textSize="20sp" /> <TextView android:id="@+id/back_right_tv_delete" android:layout_width="84dp" android:layout_height="match_parent" android:background="@android:color/holo_red_dark" android:gravity="center" android:text="Delete" android:textColor="@android:color/white" android:textSize="20sp" /> </LinearLayout> <!--2 前布局 content--> <TextView android:id="@+id/front_tv_content" android:layout_width="match_parent" android:layout_gravity="center" android:gravity="center" android:layout_height="match_parent" android:background="#666666" /> </www.weshared.qqcehua.SwipeLayout>
在MainActivity中
public class MainActivity extends AppCompatActivity { private SwipeLayout mSwipeLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); init(); } private void init() { mSwipeLayout = (SwipeLayout) findViewById(R.id.swipelayout); mSwipeLayout.setOnClickListener(new SwipeLayout.OnClickListener() { @Override public void onClick(View view) { switch (view.getId()) { case R.id.back_left_tv_mark: toast("mark"); break; case R.id.front_tv_content: toast("content"); break; case R.id.back_right_tv_call: toast("call"); break; case R.id.back_right_tv_delete: toast("delete"); break; } } }); } public void toast(String message) { Toast toast = Toast.makeText(this, "", Toast.LENGTH_SHORT); if (!TextUtils.isEmpty(message) && toast != null) { toast.setText(message); toast.show(); } } }
自定义SwipeLayout控件
public class SwipeLayout extends FrameLayout { private View mBackLeftView; private ViewGroup mBackRightView; private View mFrontView; private int mWidth; private int mHeight; private int mLeftRange; private int mRightRange; private int status; public final int NORMAL = 0;//关闭状态 public final int LEFT_OPEN = 1;//左边打开状态 public final int RIGHT_OPEN = 2;//右边打开状态 public final int LEFT_OPENING = 3;//左边正打开状态 public final int LEFT_CLOSING = 4;//左边正关闭状态 public final int RIGHT_OPENING = 5;//右边正打开状态 public final int RIGHT_CLOSING = 6;//右边正关闭状态 private ViewDragHelper mViewDrawHelper; private final int V = 300;//限制速度 private OnSwipeListener mOnSwipeListener; private OnClickListener mOnClickListener; private View mBackRightCall; private View mBackRightDelete; private int x; private boolean isClick; private final int DX = 10; public interface OnSwipeListener { void onLeftOpen(SwipeLayout swipeLayout); void onLeftClose(SwipeLayout swipeLayout); void onRightOpen(SwipeLayout swipeLayout); void onRightClose(SwipeLayout swipeLayout); } public interface OnClickListener { void onClick(View view); } public SwipeLayout(Context context) { super(context); init(); } public SwipeLayout(Context context, AttributeSet attrs) { super(context, attrs); init(); } public SwipeLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public SwipeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(); } private void init() { status = NORMAL;//默认是NORMAL mViewDrawHelper = ViewDragHelper.create(this, callback); } public void setOnSwipeListener(OnSwipeListener mOnSwipeListener) { this.mOnSwipeListener = mOnSwipeListener; } public void setOnClickListener(OnClickListener mOnClickListener) { this.mOnClickListener = mOnClickListener; } private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() { /**是否试图拖拽子view*/ @Override public boolean tryCaptureView(View child, int pointerId) { if (child == mBackLeftView) { return false; } return true; } /** 水平方向上的限制*/ @Override public int clampViewPositionHorizontal(View child, int left, int dx) { if (child == mFrontView) { if (left < -mRightRange) { left = -mRightRange; } else if (left > mLeftRange) { left = mLeftRange; } } else if (child == mBackRightView) { if (left < mWidth - mRightRange) { left = mWidth - mRightRange; } else if (left > mWidth) { left = mWidth; } } return left; } /**这是系统定义的状态*/ @Override public void onViewDragStateChanged(int state) { super.onViewDragStateChanged(state); if (state == ViewDragHelper.STATE_IDLE) {//ViewDrawHelper处于空闲状态 } else if (state == ViewDragHelper.STATE_DRAGGING) {//ViewDrawHelper处于正在拖拽状态 //拖拽状态,可设置滑动事件 } else if (state == ViewDragHelper.STATE_SETTLING) {//ViewDrawHelper处于飞翔状态 //飞翔状态设置,可设置滚动事件 } } @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { super.onViewPositionChanged(changedView, left, top, dx, dy); if (mFrontView == changedView) { mBackRightView.offsetLeftAndRight(dx); } else if (mBackRightView == changedView) { mFrontView.offsetLeftAndRight(dx); } status = updateStatus();//更新控件的状态 invalidate();//重绘界面 } @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { super.onViewReleased(releasedChild, xvel, yvel); int left = mFrontView.getLeft(); if (left < -mRightRange * 0.5f) { if (xvel > V) { normalClose(); } else { rightOpen(); } } else if (left >= -mRightRange * 0.5f && left <= 0) { if (xvel < -V) {//向左滑动 rightOpen();//打开右边前布局 } else { normalClose(); } } else if (left > 0 && left <= mLeftRange * 0.5f) { if (xvel > V) { leftOpen(); } else { normalClose(); } } else if (left > mLeftRange * 0.5f && left <= mLeftRange) { if (xvel < -V) {//向左滑动 normalClose(); } else { leftOpen(); } } } }; public void dispatchClickListener() { //设置点击事件 if (status == LEFT_OPEN) { //mark的点击事件和Content点击事件 if (mOnClickListener != null) { if (x > 0 && x < mLeftRange) { mOnClickListener.onClick(mBackLeftView); } } } else if (status == RIGHT_OPEN) { //call 和 Delete的点击事件 和Content点击事件 if (mOnClickListener != null) { if (x > mWidth - mRightRange && x < mWidth - mRightRange * 0.5f) { mOnClickListener.onClick(mBackRightCall); } else if (x >= mWidth - mRightRange * 0.5f && x <= mWidth) { mOnClickListener.onClick(mBackRightDelete); } } } else if (status == NORMAL) { //content的点击事件 if (mOnClickListener != null) { mOnClickListener.onClick(mFrontView); } } } private int updateStatus() { int left = mFrontView.getLeft(); if (left == -mRightRange) { status = RIGHT_OPEN; } else if (left == 0) { status = NORMAL; } else if (left == mLeftRange) { status = LEFT_OPEN; } return status; } public void leftOpen() { leftOpen(true); } public void leftOpen(boolean isSmooth) { int finalLeft = mLeftRange; int finalTop = 0; if (isSmooth) { if (mViewDrawHelper.smoothSlideViewTo(mFrontView, finalLeft, finalTop)) { ViewCompat.postInvalidateOnAnimation(this); } } else { layoutContent(LEFT_OPEN); } } public void normalClose() { normalClose(true); } public void normalClose(boolean isSmooth) { int finalLeft = 0; int finalTop = 0; if (isSmooth) { if (mViewDrawHelper.smoothSlideViewTo(mFrontView, finalLeft, finalTop)) { ViewCompat.postInvalidateOnAnimation(this); } } else { layoutContent(NORMAL); } } public void rightOpen() { rightOpen(true); } public void rightOpen(boolean isSmooth) { int finalLeft = -mRightRange; int finalTop = 0; if (isSmooth) { if (mViewDrawHelper.smoothSlideViewTo(mFrontView, finalLeft, finalTop)) { ViewCompat.postInvalidateOnAnimation(this); } } else { layoutContent(RIGHT_OPEN); } } @Override public void computeScroll() { super.computeScroll(); if (mViewDrawHelper.continueSettling(true)) { ViewCompat.postInvalidateOnAnimation(this); } } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return mViewDrawHelper.shouldInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { dispatchOnTouchEvent(event);//分发触摸的事件 try { mViewDrawHelper.processTouchEvent(event);//将触摸事件传递给ViewDrawHelper } catch (Exception e) { } return true; } public void dispatchOnTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { x = (int) event.getX(); isClick = true; } else if (event.getAction() == MotionEvent.ACTION_MOVE) { int movex = (int) event.getX(); if (Math.abs(movex - x) > DX) {//防止点击事件,会稍微手指抖动 isClick = false; } } else if (event.getAction() == MotionEvent.ACTION_UP) { if (isClick) { dispatchClickListener(); } } } @Override protected void onFinishInflate() { super.onFinishInflate(); //获取控件中的子控件 mBackLeftView = getChildAt(0); mBackRightView = (ViewGroup) getChildAt(1); mFrontView = getChildAt(2); mBackRightCall = mBackRightView.getChildAt(0); mBackRightDelete = mBackRightView.getChildAt(1); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mWidth = getMeasuredWidth(); mHeight = getMeasuredHeight(); mLeftRange = mBackLeftView.getMeasuredWidth(); mRightRange = mBackRightView.getMeasuredWidth(); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); //摆放布局 layoutContent(NORMAL); } public void layoutContent(int status) { Rect frontRect = computeFrontRect(status);//根据状态,摆放前布局 mFrontView.layout(frontRect.left, frontRect.top, frontRect.right, frontRect.bottom); Rect rightBackRect = computeRightBackRect(frontRect);//根据前布局,摆放右边后布局 mBackRightView.layout(rightBackRect.left, rightBackRect.top, rightBackRect.right, rightBackRect.bottom); } public Rect computeFrontRect(int status) { int left = 0; int top = 0; if (status == LEFT_OPEN) { left = mLeftRange; } else if (status == RIGHT_OPEN) { left = -mRightRange; } return new Rect(left, top, left + mWidth, top + mHeight); } public Rect computeRightBackRect(Rect frontRect) { int left = 0; int top = 0; if (frontRect != null) { left = frontRect.right; } return new Rect(left, top, left + mRightRange, top + mHeight); } }
现在控件耦合程度太高,以后慢慢优化,写成一个库。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
- 有料 | 无人驾驶登机桥首次在深圳试行
- java学习:eclipse + Weblogic 12c + svn 集成开发环境搭建
- Docker容器学习梳理--容器登陆方法梳理(attach、exec、nsenter)
- java学习:调用 java web service
- java学习:数据增删改查、存储过程调用及事务处理
- 极客手工:自制51四驱无线遥控小车
- flash:二次贝塞尔曲线应用-生成飞机路径示意图
- 微信小程序重磅功能上线!一键连Wi-Fi/手机变门禁卡
- MySQL下载安装、基本配置、问题处理
- windows下命令行模式中cd命令无效的原因
- 分布式和集群区别?什么是云计算平台?分布式的应用场景?
- 中国移动也要搞自动驾驶,没了SIM卡怎么耍花样?
- python并发编程之多进程理论部分
- 使用concurrent.futures模块并发,实现进程池、线程池
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- docker环境搭建nexus私有maven私服
- mysql每天定时自动全库备份、灾备、docker
- wails Go+vue/angular/react编写桌面GUI客户端
- GIT仓库、源码管理服务器gitea的安装、htttps访问
- 微信小程序显示当前系统年月日时分秒
- 【每日一题】40. Combination Sum II
- nginx url自动301加斜杠
- 【剑指offer】47.求1+2+3+...+n
- 【剑指offer】48.不用加减乘除做加法
- Gradle 6.6 发布,引入配置缓存特性,大幅提升构建性能
- 61.Vue 结合webpack使用vue-router
- 拨云见日:揭开ORA-00600:[4193]的神秘面纱
- AUCell | 识别单细胞对“基因集”的响应
- 未来十年,机器学习工程师会消失吗?
- Get了!用Python制作数据预测集成工具 | 附代码