Android进阶-纯粹自定义控件二

原创 2015年11月19日 20:36:42

Android进阶-纯粹自定义控件二

本文来看一下自定义ViewGroup需要注意哪些。
以自定义的一个侧滑菜单为例。
图例:
这里写图片描述


  • 关键点

  • 既然是自定义的ViewGroup, 那么的话,控件的具体内容肯定不是要考虑的事情
  • 这个ViewGroup应考虑的是
    • 我们这个ViewGroup有何特点? -> 子View的行为
    • 如何完成自己的 onMeasure(), onLayout()方法,从而控制子View
    • 如何去实现子View的行为

侧滑菜单

  • 这个ViewGroup所具有的特点为:
    • 拥有两个子View,正常状态下,一个可见,一个不可见
    • 可以通过滑动,来控制子View的显示
    • 可以给外界暴露一个借口,来控制隐藏的View显示

实现关键点

  • 如何得到得到子View的引用,从而实现对子View的控制

    • 首先,在构造方法中是得不到的,构造知识把自己给弄出来了
    • 可以覆写protected void onFinishInflate()
      • 这个方法会在所有的子View被inflate之后调用
      • 因此可以通过ViewGroup.getChildAt(position)来得到子View的引用
  • onMeasure方法

    • protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    • widthMeasureSpec和heightMeasureSpec在前面已经说过,这是View的父View传递给他的测量值
    • 我们可以利用这两个参数,来对子View执行测量
    • 不过,在自定义ViewGroup方法时,一般重写这个方法,因为这个方法主要就是用来测量出(依据父View和布局文件中的参数)子View的宽高
    • 我们可以借用其他的ViewGroup的方法, 因此我们可以通过继承来实现(例如继承FrameLayout)
    • 来看一下系统是如何对View进行测量的(我们也可以这么干)
      • 系统测量依赖 MeasureSpec 的 public static int makeMeasureSpec (int size, int mode)方法
      • size代表在布局文件中的宽高的值, mode代表解析这个宽高的模式
      • mode可取: UNSPECIFIED(wrap_content) EXACTLY(精确规定了大小,例如多少dp) AT_MOST(比如math_parent)
      • 例如: int measureSpecWidth = MeasureSpec.makeMeasureSpec(childViewWidth, MeasureSpec.EXACTLY);
  • 如何使一个View隐藏,一个View展示

    • 这肯定是关于子View如何布局,即我们自定义的这个ViewGroup在最初对子View进行布局时, 一个充满屏幕(父View),一个在屏幕外面
    • 上面的实现应在onLayout()方法中

可以这样实现:

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        menuView.layout(-menuWidth, 0, 0, menuView.getMeasuredHeight());  //在外面
        mainView.layout(0, 0, r, b); //充满父View
    }
  • 处理用户滑动,两个View显示的问题

    • 当用户向右滑动是,肯定是要是menuView显示出来

      • 有3中方法可以做到这一点(控制子View的移动显示)
        • layout(l, t, r, b) 很好理解,再布一次局就是了
        • offsetTopAndBottom()和offsetLeftAndRight()
        • scrollTo()
          • 将View的边框向(x, y)滑动, 会引起重绘, 这个x, y并没什么限制, 就向在一张大纸上滑动
          • getScrollX (), 得到已经滑动的距离
    • 使用scrollTo()方法来完成子View的滑动效果

      • 我们滑动的是ViewGroup的边框(屏幕的边框)
      • 由相对论,我们可以得出,我们向右滑动,右边的内容就显示出来了,想左滑动,左边的内容就显示出来了
      • 反正就是,你想把左边的隐藏的menuView给滑动出来, 调用scrollTo()时就得向左滑!(得给负值)
    • 即我们在触摸滑动中可以这样处理
      如下

      //向右滑slideLength 是正的, 向左滑slideLength是负的
      int newScrollX = getScrollX() - slideLength;      //上次滑动的距离 - 这次滑动的距离
      if(newScrollX<-menuWidth)
          newScrollX = -menuWidth;     //最大滑动距离, 不能超出menuView的宽
      if(newScrollX>0)newScrollX = 0;  //     不能向左滑
      scrollTo(newScrollX, 0);      
      
  • 暴露出给用户直接显示menuView和关闭menuView的接口

    • 其实这两个接口,就是能够使用户通过调用这两个接口来完成menuView的显示
    • 直接实现的话很简单, 就向上面的代码, 滑出来就是
    • 但是, 一次滑动到指定位置,太快,用户体验不好
    • 因此我们需要,让menuView在一定的时间内滑动出来哦
    • 实现这个问题,共有两种办法

1)使用自定义动画,

/**
 * 这个动画让指定view在一段时间内scrollTo到指定位置
 */
    public class ScrollAnimation extends Animation{

        private View view;
        private int targetScrollX;
        private int startScrollX;
        private int totalValue;

        public ScrollAnimation(View view, int targetScrollX) {
            super();
            this.view = view;
            this.targetScrollX = targetScrollX;

            startScrollX = view.getScrollX();
            totalValue = this.targetScrollX - startScrollX;

            int time = Math.abs(totalValue);  
            setDuration(time);      //实现,依据滑动的距离,来决定滑动动画时间的长与短
        }
    /**
     * 在指定的时间内一直执行该方法,直到动画结束
     * interpolatedTime:0-1  标识动画执行的进度或者百分比
     * 当前的值 = 起始值 + 总的差值*interpolatedTime
     */
        @Override
        protected void applyTransformation(float interpolatedTime,
                Transformation t) {
            super.applyTransformation(interpolatedTime, t);
            int currentScrollX = (int) (startScrollX + totalValue*interpolatedTime);
            view.scrollTo(currentScrollX, 0);
        }
    }

2)利用Scroller, 它可以模拟一个移动的过程,但并不会是View真正移动

    private void closeMenu(){
        scroller.startScroll(getScrollX(), 0, 0-getScrollX(), 0, 400);
        invalidate();
    }

    private void openMenu(){
        scroller.startScroll(getScrollX(), 0, -menuWidth-getScrollX(), 0, 400);
        invalidate();
    }
/**
 * Scroller不主动去调用这个方法
 * 而invalidate()可以掉这个方法
 * invalidate->draw->computeScroll
 */
    @Override
    public void computeScroll() {  //这个方法
        super.computeScroll();
        if(scroller.computeScrollOffset()){//返回true,表示动画没结束, 当计算的滑动的值到我们模拟滑动的地方就停止
            scrollTo(scroller.getCurrX(), 0);
            invalidate();   
        }
    }
版权声明:本文为博主原创文章,未经博主允许不得转载。

Android进阶——自定义View之必学的系统控件架构及自定义控件概述

Android系统框架的高度开源和可扩展性,为我们提供了一个自定义View开发的大体框架,但真正的完全掌握也是有一点难度的,毕竟自定义View的需求有时候是源自产品参考IOS、或者其他系统的效果,笔者...
  • CrazyMo_
  • CrazyMo_
  • 2016年11月30日 17:15
  • 887

android 纯粹自定义控件 滑动开关

滑动开关: 测量:设置自己显示在屏幕上的宽高  onMeasure 布局:设置自己显示在屏幕上的位置(只有在自定义的viewGroup中才用到)  onLayout 绘制:控制显示在屏幕上的样子(自定...
  • CSDNYUANDAIMAXUEXI
  • CSDNYUANDAIMAXUEXI
  • 2016年04月13日 15:37
  • 289

Android进阶之自定义控件二

了解自定义控件的三大流程(measure、layout、draw)在上一篇博客中我们大致介绍了一下View和ViewGroup,接下来我们就学习一下自定义控件的三大流程,为我们打下夯实的基础。(本博客...
  • u010083327
  • u010083327
  • 2017年02月23日 16:51
  • 138

Hadoop入门进阶步步高(一)-环境准备

前言Hadoop从存储上来说,是类似于冗余磁盘阵列(RAID)的存储方式,将数据分散存储并提供以提供吞吐量,它的存储系统就是HDFS(Hadoop Distuibute Fils System);从计...
  • fenglibing
  • fenglibing
  • 2014年06月15日 21:53
  • 9158

Android进阶-自定义控件一

Android进阶-自定义控件一 自定义控件的分类组合控件:将系统原生控件组合起来,加上动画效果,形成一种特殊的UI特效 纯粹自定义控件:继承系统View,自己去实现View效果 旋转动画的注意点 ...
  • sdlg2015
  • sdlg2015
  • 2015年11月19日 20:35
  • 157

Android自定义控件进阶

上回我们已经实现了一个简单的自定义控件(不知道的朋友戳这里) 只是这里的控件还不能给它添加点击事件,也不能给他人方便的调用 接下来就给大家介绍一下解决的办法:接口回调 1.首先需要在我们的Topb...
  • hssg380
  • hssg380
  • 2015年03月24日 18:51
  • 289

Android 自定义控件进阶:图文混排

转载至:http://blog.csdn.net/lmj623565791/article/details/24300125首先我们来看一下要达到的效果:继续自定义View之旅,前面已经介绍过一个自定...
  • jingbin_
  • jingbin_
  • 2016年11月05日 00:50
  • 542

C#自定义控件小结进阶篇

写在前面:本篇重点列举了.Net的winForm平台与wpf平台的基础编程技术文章,这些文章都使用了详细的编程实例,配合简洁的描述。是.net gdi学习者重要的技术参考。 1.      GD...
  • biyusr
  • biyusr
  • 2012年02月03日 14:55
  • 2568

Android程序员的进阶之路

本文主要论述的是android程序员的进阶之路,博主本人就是一名android开发攻城狮,所以这里讲述的大多数是android开发攻城狮的技术进阶之路,如有问题请多指正。大家都知道程序员之中有有菜鸟程...
  • qq_23547831
  • qq_23547831
  • 2016年01月28日 17:03
  • 11509

Android进阶学习内容整理

我是个喜欢不断学习新知识,探索新东西的人,无论是对于技术还是生活,我都有着足够的好奇心,我觉得只有这样,人生才会更快乐一些。然而,在学习的过程中,归纳和总结知识,整合资源的能力也是非常重要的。所以,今...
  • pangrongxian
  • pangrongxian
  • 2016年04月09日 21:11
  • 2217
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android进阶-纯粹自定义控件二
举报原因:
原因补充:

(最多只允许输入30个字)