Android 中 SwipeLayout一个展示条目底层菜单的侧滑控件源码解析

由于项目上的需要侧滑条目展示收藏按钮,记得之前代码家有写过一个厉害的开源控件 AndroidSwipeLayout 本来准备直接拿来使用,但是看过 issue 发现现在有不少使用者反应有不少的 bug ,而且代码家现在貌似也不进行维护了.故自己实现了一个所要效果的一个控件.因为只是实现我需要的效果,所以大家也能看到,代码里有不少地方我是写死的.希望对大家有些帮助.而且暂时也不需要 AndroidSwipeLayout 大而全的功能,算是变相给自己做的项目精简代码了.

完整示例代码请看:GitHub 地址

主要源码:

public class SwipeLayout extends FrameLayout {
public static final int CLOSE = 0;
public static final int OPEN = 1;
private int mState = CLOSE;
private int mWidth;
private int mHeight;
private float mDownX;
private float mDownY;
private SwipeListener mSwipeListener;
private View mTopView;
private View mBottomView;
private ViewDragHelper mViewDragHelper;
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);
mViewDragHelper = ViewDragHelper.create(this, new ViewDragHelper.Callback() {
@Override
public boolean tryCaptureView(View child, int pointerId) {//只对mTopView进行处理
return child == mTopView;
}
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {//设置横向滑动的边界(left的值是mTopView左上角点的x坐标值)
int newLeft;
if (left <= -mBottomView.getMeasuredWidth()) {
newLeft = -mBottomView.getMeasuredWidth();
} else if (left >= 0) {
newLeft = 0;
} else {
newLeft = left;
}
return newLeft;
}
@Override
public int clampViewPositionVertical(View child, int top, int dy) {//因为不需要上下的滑动直接设置为0(top的值是mTopView左上角点的y坐标值)
return 0;
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {//手指松开时会回调该函数
int right = mWidth - releasedChild.getRight();//mTopView右边界距离屏幕右边的距离
int bottomWidth = mBottomView.getMeasuredWidth();
if (right > bottomWidth * 9 / 10) {
scrollToLeftEdge();
return;
}
if (right <= bottomWidth / 10 && right > 0) {
scrollToRightEdge();
return;
}
if (xvel == 0) {//速度为0时单独处理
if (right >= bottomWidth / 2) {
scrollToLeftEdge();
} else if (right < bottomWidth / 2) {
scrollToRightEdge();
}
return;
}
if (xvel > 0) {//向右滑动后松手
scrollToRightEdge();
} else {//向左滑动后松手
scrollToLeftEdge();
}
}
});
}
@Override
public void computeScroll() {
if (mViewDragHelper.continueSettling(true)) {
invalidate();
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownX = ev.getRawX();
mDownY = ev.getRawY();
if (mState == CLOSE) {
return true;
}
break;
case MotionEvent.ACTION_MOVE:
float distanceX = ev.getRawX() - mDownX;
float distanceY = ev.getRawY() - mDownY;
float angle;
if (distanceX == 0) {
angle = 90;
} else {
angle = (float) Math.toDegrees(Math.atan(Math.abs(distanceY / distanceX)));
}
if (angle < 45) {
return true;//拦截事件交给自己处理滑动
}
break;
}
return mViewDragHelper.shouldInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
ViewParent viewParent = getParent();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownX = ev.getRawX();
mDownY = ev.getRawY();
break;
case MotionEvent.ACTION_MOVE:
float distanceX = ev.getRawX() - mDownX;
float distanceY = ev.getRawY() - mDownY;
float angle;
if (distanceX == 0) {
angle = 90;
} else {
angle = (float) Math.toDegrees(Math.atan(Math.abs(distanceY / distanceX)));
}
if (angle < 45 && viewParent != null) {
viewParent.requestDisallowInterceptTouchEvent(true);//让父控件不要处理事件,交给子控件
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (viewParent != null) {
viewParent.requestDisallowInterceptTouchEvent(false);
}
break;
}
mViewDragHelper.processTouchEvent(ev);
return true;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
int measureHeight = mBottomView.getMeasuredHeight();
int measureWidth = mBottomView.getMeasuredWidth();
mBottomView.layout(mWidth - measureWidth, (mHeight - measureHeight) / 2, mWidth, mHeight + measureHeight / 2);//靠右边界垂直居中
if (mState == OPEN) {
mTopView.layout(-measureWidth, 0, mTopView.getMeasuredWidth() - measureWidth, mTopView.getMeasuredHeight());
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = w;
mHeight = h;
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
if (getChildCount() != 2) {
throw new IllegalStateException("only and should contain two child view");
}
View bottomView = getChildAt(0);
if (!(bottomView instanceof ViewGroup)) {
throw new IllegalStateException("sideslip menu should be contained by a viewgroup");
}
mBottomView = bottomView;
mTopView = getChildAt(1);
}
//回滚到左边(只能在onViewReleased里使用该方法)
private void scrollToLeftEdge() {
mViewDragHelper.settleCapturedViewAt(-mBottomView.getMeasuredWidth(), 0);
invalidate();
mState = OPEN;
if (mSwipeListener != null) {
mSwipeListener.onOpenListener(this);
}
}
//回滚到右边(只能在onViewReleased里使用该方法)
private void scrollToRightEdge() {
mViewDragHelper.settleCapturedViewAt(0, 0);
invalidate();
mState = CLOSE;
}
public void smoothClose() {
mViewDragHelper.smoothSlideViewTo(mTopView, 0, 0);
invalidate();
mState = CLOSE;
}
public int getState() {
return mState;
}
public void setState(int state) {
mState = state;
invalidate();
}
public interface SwipeListener {
void onOpenListener(SwipeLayout swipeLayout);
}
public void setSwipeListener(SwipeListener mSwipeListener) {
this.mSwipeListener = mSwipeListener;
}
}

效果图

以上所述是小编给大家介绍的Android 中 SwipeLayout一个展示条目底层菜单的侧滑控件源码解析,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • Android控件之菜单的创建方式

    显示效果图: 第一种创建方式 ------- package com.example.androidthismenus; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; public class MainActivity extends Activity { @Override protected void onCreate

  • Android自定义控件实现底部菜单(上)

    今天我们封装一个底部的菜单栏,这个大多数的应用都会用到,因此我们来自定义,方便以后项目的使用. 该控件的实现将分上下篇来介绍,先来看一个菜单栏的子控件–MenuItemM,这个控件有什么用呢?我们来看下一些主流app上的一些控件,如: 以上三张图片分别来自微信,今日头条和去哪儿,接下来我们将看到如何通过一个控件来实现不同的效果. 首先看下我写的一个deme 可以看到标题栏的消息控件,以及底部三个菜单项都是通过MenuItemM来实现的 这里面只是演示菜单栏的子控件,我们将在下一篇博客中完成底部菜

  • Android控件View打造完美的自定义侧滑菜单

    一.概述 在App中,经常会出现侧滑菜单,侧滑滑出View等效果,虽然说Android有很多第三方开源库,但是实际上咱们可以自己也写一个自定义的侧滑View控件,其实不难,主要涉及到以下几个要点: 1.对Android中Window类中的DecorView有所了解 2.对Scroller类实现平滑移动效果 3.自定义ViewGroup的实现 首先来看看效果图吧:     下面现在就来说说这里咱们实现侧滑View的基本思路吧,这里我采用的是自定义一个继承于RelativeLayout的控件叫做XC

  • Android自定义控件案例汇总1(菜单、popupwindow、viewpager)

    自定义控件是根据自己的需要自己来编写控件.安卓自带的控件有时候无法满足你的需求,这种时候,我们只能去自己去实现适合项目的控件.同时,安卓也允许你去继承已经存在的控件或者实现你自己的控件以便优化界面和创造更加丰富的用户体验.在平常的项目中,我们 人为的把自定义控件分为两种:一种是组合方式实现.一种是通过继承view或viewgroup及其子类实现.两者都可以实现我们想要的效果,因此,我们可以根据自己的需求,选择合适的方案.本文以案例的形式来显示几种较为常见的自定义控件. 案例一 优酷菜单: 功能介

  • Android自定义控件实现底部菜单(下)

    在app中经常会用到底部菜单的控件,每次都需要写好多代码,今天我们用到了前几篇博客里的控件来进一步封装底部菜单.先看效果图: 主要包括以下功能: 1 设置icon以及点击之后的icon 2 设置文字 3 设置文字颜色以及点击之后的文字颜色 4 设置未读数量.更多以及new 我们先看如何使用,然后再看如何实现的 1 在布局文件中引用MenuM <com.landptf.view.MenuM android:id="@+id/mm_bottom" android:layout_wid

  • Android自定义控件之仿优酷菜单

    去年的优酷HD版有过这样一种菜单,如下图: 应用打开之后,先是三个弧形的三级菜单,点击实体键menu之后,这三个菜单依次旋转退出,再点击实体键menu之后,一级菜单会旋转进入,点击一级菜单,二级菜单旋转进入,点击二级菜单的menu键,三级菜单旋转进入,再次点击二级菜单的旋转键,三级菜单又会旋转退出,这时再点击一级菜单,二级菜单退出,最后点击实体menu键,一级菜单退出. 总体来说实现这样的功能: (1)点击实体menu键时,如果界面上有菜单显示,不管有几个,全部依次退出,如果界面上没有菜单显示,

  • Android使用自定义控件HorizontalScrollView打造史上最简单的侧滑菜单

    侧滑菜单在很多应用中都会见到,最近QQ5.0侧滑还玩了点花样~~对于侧滑菜单,一般大家都会自定义ViewGroup,然后隐藏菜单栏,当手指滑动时,通过Scroller或者不断的改变leftMargin等实现:多少都有点复杂,完成以后还需要对滑动冲突等进行处理~~今天给大家带来一个简单的实现,史上最简单有点夸张,但是的确是我目前遇到过的最简单的一种实现~~~ 1.原理分析 既然是侧滑,无非就是在巴掌大的屏幕,塞入大概两巴掌大的布局,需要滑动可以出现另一个,既然这样,大家为啥不考虑使用Android

  • Android编程之下拉菜单Spinner控件用法示例

    本文实例讲述了Android下拉菜单Spinner控件用法.分享给大家供大家参考,具体如下: activity_main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent

  • Android自定义控件简单实现侧滑菜单效果

    侧滑菜单在很多应用中都会见到,最近QQ5.0侧滑还玩了点花样~~对于侧滑菜单,一般大家都会自定义ViewGroup,然后隐藏菜单栏,当手指滑动时,通过Scroller或者不断的改变leftMargin等实现:多少都有点复杂,完成以后还需要对滑动冲突等进行处理~~今天给大家带来一个简单的实现,史上最简单有点夸张,但是的确是我目前遇到过的最简单的一种实现~~~ 1.原理分析 既然是侧滑,无非就是在巴掌大的屏幕,塞入大概两巴掌大的布局,需要滑动可以出现另一个,既然这样,大家为啥不考虑使用Android

  • Android 中 SwipeLayout一个展示条目底层菜单的侧滑控件源码解析

    由于项目上的需要侧滑条目展示收藏按钮,记得之前代码家有写过一个厉害的开源控件 AndroidSwipeLayout 本来准备直接拿来使用,但是看过 issue 发现现在有不少使用者反应有不少的 bug ,而且代码家现在貌似也不进行维护了.故自己实现了一个所要效果的一个控件.因为只是实现我需要的效果,所以大家也能看到,代码里有不少地方我是写死的.希望对大家有些帮助.而且暂时也不需要 AndroidSwipeLayout 大而全的功能,算是变相给自己做的项目精简代码了. 完整示例代码请看:GitHu

  • java底层组合AQS实现类kReentrantLock源码解析

    目录 不啰嗦,我们直接开始! 引导语 上两小节我们学习了 AQS,本章我们就要来学习一下第一个 AQS 的实现类:ReentrantLock,看看其底层是如何组合 AQS ,实现了自己的那些功能. 本章的描述思路是先描述清楚 ReentrantLock 的构成组件,然后使用加锁和释放锁的方法把这些组件串起来. 1.类注释 ReentrantLock 中文我们习惯叫做可重入互斥锁,可重入的意思是同一个线程可以对同一个共享资源重复的加锁或释放锁,互斥就是 AQS 中的排它锁的意思,只允许一个线程获得

  • Android中ImageView.src设置图片拉伸、填满控件的方法

    问题 ImageView.src设置图片资源,图片不拉伸了,却有空隙部分: <LinearLayout android:id="@+id/linearLayout1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" > <ImageView andro

  • 分享一个我自己写的ToolTip提示插件(附源码)

    继续分享一个我自己写的 ToolTip提示插件,希望大家支持我,给我点评论,哪怕骂我的也好啊,让我知道有人在关注我"小豆" 嘿嘿.废话不多说上代码! 复制代码 代码如下: $.fn.ToolTip = function (option) { var defaults = { direction: "down", star: function () { }, from: $(this), url: '../images/arrow.png' }; //方法内基础变量

  • Android中自定义一个View的方法详解

    本文实例讲述了Android中自定义一个View的方法.分享给大家供大家参考,具体如下: Android中自定义View的实现比较简单,无非就是继承父类,然后重载方法,即便如此,在实际编码中难免会遇到一些坑,我把自己遇到的一些问题和解决方法总结一下,希望对广大码友们有所帮助. 注意点① 用xml定义Layout时,Root element 最好使用merge 当我们需要继承一个布局比较复杂的ViewGroup(比较多的是LinearLayout.RelativeLayout)时,通常会用xml来

  • 如何在android中制作一个方向轮盘详解

    目录 先上效果图 原理很简单,其实就是一个自定义的view 计算滑块位置的原理: 通用性很好的接口: 小技巧: 代码部分 写在最后: 先上效果图 原理很简单,其实就是一个自定义的view 通过观察,很容易发现,我们自己的轮盘就两个view需要绘制,一个是外面的圆盘,一个就随手指移动的滑块: 外面的圆盘很好绘制,内部的滑块则需要采集手指的位置,根据手指的位置计算出滑块在大圆内的位置: 最后,我们做的UI不是单纯做一个UI吧,肯定还是要用于实际应用中去,所以要加一个通用性很好的回调. 计算滑块位置的

  • Android源码解析onResume方法中获取不到View宽高

    目录 前言 问题1.为什么onCreate和onResume中获取不到view的宽高? 问题2.为什么View.post为什么可以获取View宽高? 结论 前言 有一个经典的问题,我们在Activity的onCreate中可以获取View的宽高吗?onResume中呢? 对于这类八股问题,只要看过都能很容易得出答案:不能. 紧跟着追问一个,那为什么View.post为什么可以获取View宽高? 今天来看看这些问题,到底为何? 今日份问题: 为什么onCreate和onResume中获取不到vie

  • Android下拉刷新控件PullToRefresh实例解析

    Android中很多时候都会用到上下拉刷新,这是一个很常用的功能,Android的v4包中也为我们提供了一种原生的下拉刷新控件--SwipeRefreshLayout,可以用它实现一个简洁的刷新效果,但今天我们的主角并不是它,而是一个很火的第三方的上下拉刷新控件--PullToRefresh.PullToRefresh包括PullToRefreshScrollView.PullToRefreshListView.PullToRefreshGridView等等很多为我们提供的控件,我们可以在xml

  • Android官方的侧滑控件DrawerLayout的示例代码

    导语 侧滑控件,以前大家用的可能是三方的SlidingMenu控件,最近在看谷歌源码项目,意外的看到一个 DrawerLayout 控件.上网一查,原来这个控件是官方给我们提供的一个侧滑菜单控件.既然谷歌已经提供了一个侧滑控件,我们又何必去用一个三方的SlidingMenu控件来实现相同的效果.于是,我决定自己手敲一个Demo来实现看看. 1.DrawerLayout效果图 2.DrawerLayout 的介绍 DrawerLayout的官方文档介绍链接:http://androiddoc.qi

  • Android Handler,Message,MessageQueue,Loper源码解析详解

    本文主要是对Handler和消息循环的实现原理进行源码分析,如果不熟悉Handler可以参见博文< Android中Handler的使用>,里面对Android为何以引入Handler机制以及如何使用Handler做了讲解. 概括来说,Handler是Android中引入的一种让开发者参与处理线程中消息循环的机制.我们在使用Handler的时候与Message打交道最多,Message是Hanlder机制向开发人员暴露出来的相关类,可以通过Message类完成大部分操作Handler的功能.但

随机推荐