先看效果图:

先来说说思路:我们把该页面分为两部分,分别是头部的抽屉布局(海洋色背景)和主内容布局(白色背景),这两部分的布局是呈线性关系,即抽屉在上,主页面在下,并且它们的父布局应该是一个可滑动的LinearLayout线性布局

所以,我们的目标就是自定义一个可滑动的LinearLayout,并且设置它的子布局都向上移动一个自定义LinearLayout的高度

一、自定义控件的测量和布局

自定义LinearLayout,假设为MyPullDownLayout:

public class MyPullDownLayout extends LinearLayout {public MyPullDownLayout(Context context, @Nullable AttributeSet attrs) {super(context, attrs);}
}

我们先对子控件进行简单的测量:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);//测量子控件的大小for(int i=0;i<getChildCount();i++){View view=getChildAt(i);measureChild(view,widthMeasureSpec,heightMeasureSpec);}
}

在onLayout中设置每一个子控件的位置:

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {super.onLayout(changed, l,t, r, b);int height=getVerticalHeight();//设置子控件的位置for(int i=0;i<getChildCount();i++){View view=getChildAt(i);view.layout(view.getLeft(),view.getTop()-height,view.getRight(),view.getBottom()-height);}
}private int getVerticalHeight(){return getHeight()-getPaddingBottom()-getPaddingTop();
}

int height = getVerticalHeight() 即为这个自定义控件的高度,并让每个子控件都向上移动一个height的高度

二、自定义控件的滑动实现

我们创建一个手势检测器(GestureDetector)来辅助我们滑动控件:

private int currentPos=0;
private GestureDetector detector=new GestureDetector(new GestureDetector.SimpleOnGestureListener(){public boolean onScroll(MotionEvent e1, MotionEvent e2,float distanceX, float distanceY) {//相对滑动:Y方向滑动多少距离,view就跟着滑动多少距离//手指向上滑动if(e2.getY()<e1.getY()&&getScrollY()>=0){//滑到的y值超过0时,反弹回去if(getScrollY()>0)scrollBy(0,-getScrollY());//否则什么也不做}else if(getScrollY()<=0){//如果手指向下滑动并且没有超过抽屉页的滑动范围,就滑动页面if(!(e2.getY()>e1.getY()&&getScrollY()==-getVerticalHeight())){scrollBy(0,(int)distanceY);//手指向下滑动if(e2.getY()>e1.getY())currentPos=getScrollY()/(getVerticalHeight()/4);//手指向上滑动else currentPos=getScrollY()/(4*getVerticalHeight()/5);if(currentPos>0)currentPos=0;if(currentPos<-1)currentPos=-1;}}return super.onScroll(e1,e2,distanceX,distanceY);}
});
@Override
public boolean onTouchEvent(MotionEvent event) {//将event信息传给detector;detector.onTouchEvent(event);
}
private int getVerticalHeight(){return getHeight()-getPaddingBottom()-getPaddingTop();
}

getScrollY():y轴方向已经滑动的距离。如果在抽屉页,则getScrollY()为负数

currentPos:手指离开屏幕后,控件所在的位置(抽屉页或者主页面)

currentPos=getScrollY()/(getVerticalHeight()/4):只需滑动1/4控件高度的距离就可以自动滑动到抽屉页

currentPos=getScrollY()/(4*getVerticalHeight()/5):只需滑动1-4/5=1/5控件高度的距离就可以自动滑动到主页面

 创建Scorller对象来实现页面的自动滑动效果:

private Scroller scroller;
public MyPullDownLayout(Context context, @Nullable AttributeSet attrs) {super(context, attrs);init();
}
private void init(){scroller=new Scroller(getContext());
}@Override
public boolean onTouchEvent(MotionEvent event) {//将event信息传给detector;detector.onTouchEvent(event);switch (event.getAction()){case MotionEvent.ACTION_UP://手指离开屏幕后开始自动滑动scroller.startScroll(0,getScrollY(),0,getVerticalHeight()*currentPos-getScrollY());invalidate();break;}return true;
}@Override
public void computeScroll() {if(scroller.computeScrollOffset()){scrollTo(0,scroller.getCurrY());postInvalidateDelayed(10);}
}

scroller.startScroll():前两个参数是x,y方向已经滑动的距离,后两个参数是x,y方向还需要滑动的距离

computeScroll():利用scroller.getCurrY()每次滑动一点点距离,调用postInvalidateDelayed(10)后会回调该方法

三、XML布局文件注意事项

为了体现抽屉控件的宽高占整个父控件宽高的效果,需要把抽屉布局(Layout)的width和height设为match_parent。然后主页面布局部分就放在抽屉布局的下方,具体代码如下:

<?xml version="1.0" encoding="utf-8"?>
<com.myviewtext.MyPullDownLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:background="@mipmap/bg"><TextViewandroid:layout_width="wrap_content"android:layout_height="50dp"android:text="蜀道之难,难于上青天!"android:textColor="@color/white"/><TextViewandroid:layout_width="wrap_content"android:layout_height="50dp"android:text="蚕丛及鱼凫,开国何茫然!"android:textColor="@color/white"/><TextViewandroid:layout_width="wrap_content"android:layout_height="50dp"android:text="尔来四万八千岁,不与秦塞通人烟。西当太白有鸟道,可以横绝峨眉巅。"android:textColor="@color/white"/><TextViewandroid:layout_width="wrap_content"android:layout_height="50dp"android:text="地崩山摧壮士死,然后天梯石栈相钩连。"android:textColor="@color/white"/></LinearLayout><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="臣本布衣,躬耕南阳,苟全性命于乱世,不求闻达于诸侯。"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="先帝不以臣卑鄙,猥自枉屈,三顾臣于草庐之中,谘臣以当世之事,由是感激,遂许先帝以驱驰。"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="后值倾覆,受任于败军之际,奉命于危难之间:尔来二十有一年矣。"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="先帝知臣谨慎,故临崩寄臣以大事也。受命以来,夙夜忧虑,恐付托不效,以伤先帝之明;故五月渡泸,深入不毛。"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="今南方已定,甲兵已足,当奖帅三军,北定中原,庶竭驽钝,攘除奸凶,兴复汉室,还于旧都。"/>
</com.hualinfo.myviewtext.MyPullDownLayout>

自定义LinearLayout完整代码如下:

public class MyPullDownLayout extends LinearLayout {private int currentPos=0;private Scroller scroller;public MyPullDownLayout(Context context, @Nullable AttributeSet attrs) {super(context, attrs);init();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);//测量子控件的大小for(int i=0;i<getChildCount();i++){View view=getChildAt(i);measureChild(view,widthMeasureSpec,heightMeasureSpec);}}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {super.onLayout(changed, l,t, r, b);int height=getVerticalHeight();//设置子控件的位置for(int i=0;i<getChildCount();i++){View view=getChildAt(i);view.layout(view.getLeft(),view.getTop()-height,view.getRight(),view.getBottom()-height);}}private void init(){scroller=new Scroller(getContext());}private GestureDetector detector=new GestureDetector(new GestureDetector.SimpleOnGestureListener(){public boolean onScroll(MotionEvent e1, MotionEvent e2,float distanceX, float distanceY) {//相对滑动:Y方向滑动多少距离,view就跟着滑动多少距离//手指向上滑动if(e2.getY()<e1.getY()&&getScrollY()>=0){//滑到的y值超过0时,反弹回去if(getScrollY()>0)scrollBy(0,-getScrollY());//否则什么也不做}else if(getScrollY()<=0){//如果手指向下滑动并且没有超过抽屉页的滑动范围,就滑动页面if(!(e2.getY()>e1.getY()&&getScrollY()==-getVerticalHeight())){scrollBy(0,(int)distanceY);//手指向下滑动if(e2.getY()>e1.getY())currentPos=getScrollY()/(getVerticalHeight()/4);//手指向上滑动else currentPos=getScrollY()/(4*getVerticalHeight()/5);if(currentPos>0)currentPos=0;if(currentPos < -1)currentPos=-1;}}return super.onScroll(e1,e2,distanceX,distanceY);}});@Overridepublic boolean onTouchEvent(MotionEvent event) {//将event信息传给detector;detector.onTouchEvent(event);switch (event.getAction()){case MotionEvent.ACTION_UP:scroller.startScroll(0,getScrollY(),0,getVerticalHeight()*currentPos-getScrollY());invalidate();break;}return true;}@Overridepublic void computeScroll() {if(scroller.computeScrollOffset()){scrollTo(0,scroller.getCurrY());postInvalidateDelayed(10);}}private int getVerticalHeight(){return getHeight()-getPaddingBottom()-getPaddingTop();}
}

本篇到这里就结束,下一篇我们来解决该自定义Layout与RecyclerView滑动冲突的问题:

https://blog.csdn.net/zz51233273/article/details/108355290

Android 自定义LinearLayout实现滑动下拉抽屉的功能相关推荐

  1. android 自定义顶部,Android自定义实现顶部粘性下拉刷新效果

    本文实例为大家分享了Android实现顶部粘性下拉刷新效果的具体代码,供大家参考,具体内容如下 activity_view_mv代码 xmlns:android="http://schema ...

  2. 自定义Tab切换+自定义CheckBox+light7无限滑动/下拉刷新

    这是一篇记录型的技术杂文,记录了这段时间做的一些小模块样式,正文之前先记录一下html上下标的写法,转载自 https://blog.csdn.net/bingle14/article/details ...

  3. jQuery 效果——显示隐藏/滑动/淡入淡出/自定义动画||事件切换——简洁版滑动下拉菜单

    jQuery 效果 显示隐藏效果 <!DOCTYPE html> <html lang="en"><head><meta charset= ...

  4. android禁止下拉刷新,Android开发之无痕过渡下拉刷新控件的实现思路详解

    相信大家已经对下拉刷新熟悉得不能再熟悉了,市面上的下拉刷新琳琅满目,然而有很多在我看来略有缺陷,接下来我将说明一下存在的缺陷问题,然后提供一种思路来解决这一缺陷,废话不多说!往下看嘞! 1.市面一些下 ...

  5. Android点击事件、下拉菜单、单选框实例

    Android点击事件.下拉菜单.单选框实例 点击事件 1.ClickActivity.java import android.app.Activity; import android.os.Bund ...

  6. html css 导航 左右滑动效果代码,HTML+CSS/CSS3实现滑动下拉导航栏

    HTML+CSS/CSS3实现滑动下拉导航栏 纯css实现的滑动下拉导航栏,超详细代码,以及实现中遇到的小问题 首先创建一个列表以及一些标签的全局样式 html代码 css代码 * { margin: ...

  7. 微信小程序手指拖动 出现滑动下拉效果

    该效果类似于电商小程序左侧滑动下拉的效果 scroll-y属性:允许纵向y轴滑动 scroll-x属性:允许横向x轴滑动 注意!使用竖向滚动时 必须给scroll-view一个固定高度 使用横向滚动时 ...

  8. refreshcontrol 实现下拉刷新的功能

    该组件实现下拉刷新的功能.不过该组件是用在ScrollView的内部的,为ScrollView添加一个下拉刷新的功能.当ScrollView的垂直方向的偏移量scrollY:0的时候,手指往下拖拽Sc ...

  9. ajax实现下拉列表回显,layui实现下拉复选功能的例子(包括数据的回显与上传)

    一.layui下拉复选实现的背景:实现一个管理员拥有多个权限 二. 具体实现: //依赖资源 //页面显示 角色: xm-select-search xm-select-skin="defa ...

最新文章

  1. 工作流引擎--swamp
  2. 配置交换机etherchannel
  3. web app指南之构建html5离线应用
  4. 集美大学诚毅学院计算机科学与技术学费,集美大学诚毅学院计算机科学与技术...
  5. 连接到kali linux服务器上的MySQL服务器错误
  6. mysql5.5怎么删除字段_Linux 上 Mysql5.5 只能新建表中的字段不能删除表,权限root...
  7. iPhone SE 3售价曝光:搭载A15芯片 价格依旧香
  8. 乒乓球单循环赛_乒乓球单循环赛
  9. “华为杯”山东理工大学第十届ACM程序设计竞赛 - 解题报告
  10. Sql server 2008
  11. [初级-详细]新大陆NewLand云平台Android离线程序开发(离线导入Moudle)
  12. eigen 矩阵求逆_「伴随矩阵」Eigen库 矩阵基本操作:转置矩阵,逆矩阵,伴随矩阵,特征值 - seo实验室...
  13. Linux下QtCreator不能使用搜狗输入法输入中文
  14. dell计算机在桌面不显示,你好,在吗?我的戴尔笔记本电脑桌面图标不显示为什么?...
  15. Eclipse下用JFS和Tomcat防问SQLServer数据库的以下配置
  16. JavaWeb----Ajax技术
  17. LeetCode 27 合并两个排序的链表
  18. 仲裁结果出炉,FF将绕过恒大健康获得5亿美元外部融资
  19. 现在的网页该不该兼容IE6/7
  20. 新一代深度学习框架研究

热门文章

  1. vue中实现定时器功能
  2. 15个常用的人工智能项目应用工具!
  3. 前端开发笔记3-开发小项目,kline遇到的知识点及问题
  4. dubbo灰度发布方案
  5. teamviewer 文件传输服务器关机,teamviewer进行文件传输的详细步骤讲述
  6. docker: cloud not select device driver with “capabilities:[[gpu]]“
  7. 走好安防海外市场拓展这条路 先认清这些
  8. 红米Note4X flyme9 base on Meizu17 daily
  9. 哈工大计算机科学博士,计算机科学与技术学院博士生培养方案-哈尔滨工业大学计算机学院.DOC...
  10. ArrayList类的基本使用,基本数据类型和包装类,字符串转换