7.自定义ViewGroup-下滑抽屉
1.效果

2.思路
分析效果:
1.布局分为两部分,后面部分,前面部分,默认状态后面被挡住;
2.后面不可以滑动,前面可以滑动;
3.如果前面的布局本身是可以滑动的,那么当前面布局滑动到第一个时,后面的布局才显示出来
基于以上的效果,我们自定义ViewGroup 继承自FrameLayout,使用
ViewDragHelper处理滑动事件;当前面的view 本身是可以滑动的,那么当其手指向下move的过程中需要判断前面的view是否在最顶部,从而决定是否拦截事件;
ViewDragHelper 的用法
//重点
private ViewDragHelper mDragHelper;
//初始化
mDragHelper = ViewDragHelper.create(this, mDragCallback);
ViewDragHelper.Callback mDragCallback = new ViewDragHelper.Callback() {
@Override
public boolean tryCaptureView(@NonNull View child, int pointerId) {
//只有mDragView 可以滑动
return mDragView == child;
}
@Override
public int clampViewPositionVertical(@NonNull View child, int top, int dy) {
//控制垂直方向滑动的距离
if (top < 0) {
top = 0;
}
if (top > mMenuHeight) {
top = mMenuHeight;
}
return top;
}
//当手指松开的时候回调
@Override
public void onViewReleased(@NonNull View releasedChild, float xvel, float yvel) {
int dy = mDragView.getTop();
if (dy > mMenuHeight / 2) {
//打开
mDragHelper.settleCapturedViewAt(0, mMenuHeight);
} else {
//关闭
mDragHelper.settleCapturedViewAt(0, 0);
}
invalidate();
}
};
@Override
public boolean onTouchEvent(MotionEvent event) {
//处理event事件
mDragHelper.processTouchEvent(event);
return true;
}
全部代码
class VerticalDragListView extends FrameLayout {
private static final String TAG = "VerticalDragListView";
private ViewDragHelper mDragHelper;
private View mMenuView;
private View mDragView;
private int mMenuHeight;
private boolean isOpen = false;
public VerticalDragListView(@NonNull Context context) {
this(context, null);
}
public VerticalDragListView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public VerticalDragListView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mDragHelper = ViewDragHelper.create(this, mDragCallback);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mMenuView = getChildAt(0);
mDragView = getChildAt(1);
}
ViewDragHelper.Callback mDragCallback = new ViewDragHelper.Callback() {
@Override
public boolean tryCaptureView(@NonNull View child, int pointerId) {
//只有mDragView 可以滑动
return mDragView == child;
}
@Override
public int clampViewPositionVertical(@NonNull View child, int top, int dy) {
//通过top 控制范围
if (top < 0) {
top = 0;
}
if (top > mMenuHeight) {
top = mMenuHeight;
}
return top;
}
@Override
public void onViewReleased(@NonNull View releasedChild, float xvel, float yvel) {
int dy = mDragView.getTop();
//当手指松开的时候
if (dy > mMenuHeight / 2) {
//打开
mDragHelper.settleCapturedViewAt(0, mMenuHeight);
isOpen = true;
} else {
//关闭
mDragHelper.settleCapturedViewAt(0, 0);
isOpen = false;
}
invalidate();
}
};
@Override
public void computeScroll() {
if (mDragHelper.continueSettling(true)) {
invalidate();
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mMenuHeight = mMenuView.getMeasuredHeight();
}
float downY = 0;
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (isOpen) {
return true;
}
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mDragHelper.processTouchEvent(ev);
downY = ev.getY();
break;
case MotionEvent.ACTION_MOVE:
//子view滑动到顶部&&已经到顶了
if (ev.getY() - downY > 0 && !canChildScrollUp(mDragView)) {
return true;
}
break;
}
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mDragHelper.processTouchEvent(event);
return true;
}
/**
* 判断是否可以继续向上滑
*
* @param mTarget
* @return
*/
public boolean canChildScrollUp(View mTarget) {
if (android.os.Build.VERSION.SDK_INT < 14) {
if (mTarget instanceof AbsListView) {
final AbsListView absListView = (AbsListView) mTarget;
return absListView.getChildCount() > 0
&& (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0)
.getTop() < absListView.getPaddingTop());
} else {
return mTarget.canScrollVertically(-1) || mTarget.getScrollY() > 0;
}
} else {
return mTarget.canScrollVertically(-1);
}
}
}
3.目前存在的问题
当滑动的最顶端的时候,只有松开手,再按下滑,才可以滑的动
7.自定义ViewGroup-下滑抽屉的更多相关文章
- android自定义viewgroup初步之一----抽屉菜单
转载请注明出处 http://blog.csdn.net/wingichoy/article/details/47832151 几天前在慕课网上看到鸿洋老师的 自定义卫星菜单,感觉很有意思,于是看完视 ...
- Android 自定义ViewGroup
前面几节,我们重点讨论了自定义View的三板斧,这节我们来讨论自定义ViewGroup,为什么要自定义ViewGroup,其实就是为了更好的管理View. 自定义ViewGroup无非那么几步: Ⅰ. ...
- 简单的例子了解自定义ViewGroup(一)
在Android中,控件可以分为ViewGroup控件与View控件.自定义View控件,我之前的文章已经说过.这次我们主要说一下自定义ViewGroup控件.ViewGroup是作为父控件可以包含多 ...
- Android动画效果之自定义ViewGroup添加布局动画
前言: 前面几篇文章介绍了补间动画.逐帧动画.属性动画,大部分都是针对View来实现的动画,那么该如何为了一个ViewGroup添加动画呢?今天结合自定义ViewGroup来学习一下布局动画.本文将通 ...
- Android自定义控件之自定义ViewGroup实现标签云
前言: 前面几篇讲了自定义控件绘制原理Android自定义控件之基本原理(一),自定义属性Android自定义控件之自定义属性(二),自定义组合控件Android自定义控件之自定义组合控件(三),常言 ...
- Android自定义ViewGroup
视图分类就两类,View和ViewGroup.ViewGroup是View的子类,ViewGroup可以包含所有的View(包括ViewGroup),View只能自我描绘,不能包含其他View. 然而 ...
- [Android Pro] Android开发实践:自定义ViewGroup的onLayout()分析
reference to : http://www.linuxidc.com/Linux/2014-12/110165.htm 前一篇文章主要讲了自定义View为什么要重载onMeasure()方法( ...
- android 手把手教您自定义ViewGroup(一)
1.概述 在写代码之前,我必须得问几个问题: 1.ViewGroup的职责是啥? ViewGroup相当于一个放置View的容器,并且我们在写布局xml的时候,会告诉容器(凡是以layout为开头的属 ...
- 自定义ViewGroup须知
自定义ViewGroup须知: 1.必须复写onMeasure和onLayout方法,根据容器的特性进行布局设计 2.复写onMeasure方法必须处理父布局设置宽或高为wrap_content情况下 ...
随机推荐
- Windows操作系统深入解析原理
Windows运用程序编写插口(API)是对于Windows电脑操作系统大家族的客户方式系统软件程序编写插口.在32位版本号的Windows营销推广之前,31位版本号Windows电脑操作系统的程序编 ...
- 没有wget Loading mirror speeds from cached hostfile
问题描述 新装的系统,没有一些常用命令的rpm包.使用ifconfig,报错 Loading mirror speeds from cached hostfile解决 网上解决方案是换数据下载源,但是 ...
- Kubernetes日志系统新贵Loki-Stack
Loki简介 Grafana Loki是可以组成功能齐全的日志记录堆栈的一组组件. 与其他日志记录系统不同,Loki是基于仅索引有关日志的元数据的想法而构建的:标签(就像Prometheus标签一样) ...
- 你的Idea还可用吗?不妨试试这个神器!
@ 目录 一.STS安装 1.STS下载 2.STS安装 二.STS使用 1.STS配置JDK 2.STS配置Maven 3.使用STS创建SpringBoot项目 三.优化STS 1.主题美化 2. ...
- Spring Boot系列 八、集成Kafka
一.引入依赖 <dependency> <groupId>org.springframework.kafka</groupId> <artifactId> ...
- PyQt(Python+Qt)学习随笔:QDockWidget停靠窗相关的信号
专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 QDockWidget的信号包括与属性变更相关的allowedArea ...
- 第11.1节 Python正则表达式概述
正则表达式是可匹配文本片段的模式,一个正则表达式指定了一个与之匹配的字符串集合.最简单的正则表达式为普通字符串,与它自己匹配.如正则表达式'python'与字符串'python'匹配.通过匹配,可以在 ...
- PyQt(Python+Qt)学习随笔:Designer中的QDialogButtonBox的orientation和centerButtons属性
orientation属性 orientation属性表示QDialogButtonBox的方向,缺省情况下,方向为水平方向(值为Qt.Horizontal),表示QDialogButtonBox中的 ...
- git .gitignore 忽略列表
#: 注释 # no .a files * .a //忽略以 .a结尾的 文件 # ... ! lib .a // 忽略 非 lib.a的文件 /TODO //忽略当前目录 文件名位 ...
- 【Luogu P5168】xtq玩魔塔(Kruskal 重构树 & 树状数组 & set)
Description 给定一个 \(n\) 个顶点,\(m\) 条边的无向联通图,点.边带权. 先有 \(q\) 次修改或询问,每个指令形如 \(\text{opt}\ x\ y\): \(\tex ...