zoukankan      html  css  js  c++  java
  • 源自梦想 自定义ViewGroup的整理_1

       今天说说自定义控件,稍微偏底层一点的东西。今天的主要任务是自己完全写代码,写一个ViewGroup,实现一个类似ViewPager这样的一个功能。

       大家自定义View肯定写过,不过估计写的也不多。等大家上班以后,全都是自定义的ViewViewGroup

       实现这样滑动的效果可以使用ViewPager。其实像ViewPagerListViewSlidingMenu或者popupWindow,他们都有个共同点,就是界面上的View(大小)是不变的,只是位置在变,而只要是位置在变,通通都是使用的一样的技术。它们的底层原理都是一样的。但是这些组件,不管你学多少,永远都学不完。一开始学这些组件的时候,是一种知识的积累,但学多了以后我们就要回头想一想,它们是怎么实现的。如果我们自己来做,我们怎么去实现。等到上班的时候,那些系统的组件有可能无法实现我们的要求。

       

       其中一个技术点是scrollToscrollBy这两个方法,以下面的Demo为例。

       下面的控制按钮能控制上面View的移动。

       scrollBy这个方法是View的一个方法,是一个底层的方法,所以我们在Android中看到的所有的元素都有这样的方法。这个方法是干嘛的呢,scrollBy方法使得这个View整体的移动一个距离,比如有一个viewGroup里面有很多子View,如果要想改变这些子View的位置的话,那么有几种方法呢?两种,一种是改变这个View真实的的位置,但是这样改的话,如果ViewGroup里面的子View有很多,就要把每一个子View都要做改动,像listView就是这样实现的;而如果我想将ViewGroup里面的子View整体移动,这样就不需要将每个子View都做改变了,而是可以将他们做一个整体的偏移。对ViewGroupscrollBy,就可以使ViewGroup中的所有子View都实现偏移。

       scrollBy的源码:(由当前位置再移动(x,y)的偏移量)

        /**

         * Move the scrolled position of your view. This will cause a call to

         * {@link #onScrollChanged(int, int, int, int)} and the view will be

         * invalidated.

         * @param x the amount of pixels to scroll by horizontally

         * @param y the amount of pixels to scroll by vertically

         */

        public void scrollBy(int x, int y) {

            scrollTo(mScrollX + x, mScrollY + y);

      }

      scrollTo的源码:(移动到(x,y)位置)

        /**

         * Set the scrolled position of your view. This will cause a call to

         * {@link #onScrollChanged(int, int, int, int)} and the view will be

         * invalidated.

         * @param x the x position to scroll to

         * @param y the y position to scroll to

         */

        public void scrollTo(int x, int y) {

            if (mScrollX != x || mScrollY != y) {

                int oldX = mScrollX;

                int oldY = mScrollY;

                mScrollX = x;

                mScrollY = y;

                invalidateParentCaches();

                onScrollChanged(mScrollX, mScrollY, oldX, oldY);

                if (!awakenScrollBars()) {

                    postInvalidateOnAnimation();

                }

            }

       }

      这两个方法,偏移的是View中的内容,而View自己的位置是不变的。

      

      BaiHeTest例子:(包含歌词例子)

      是一个侧边栏滑动菜单,工作中一定会去实现这样的一个效果。有的可能想到使用SlidingMenu这个开源框架,有的可能想到使用Animation

      Animation动画实现的方式,Animation的特点是只改变我们看到的效果,而不改变其真实的物理属性,所以例子中Button的物理位置是不改变的。Animation只能看做是动画,而不能做出交互式的效果。因此,使用Animation不能(准确)实现侧边栏菜单。

      scrollToscrollBy方法实现:

      帧布局,上面包含按钮,下面是侧边菜单。直接上面布局scrollTo到一个位置(-200,0),(负值往右偏移),使用一个flag判断是否已经打开了。这样可以实现。如果想看起来有个类似动画的效果,可以使用下面两句代替scrollTo

       scroller.startScroll(layout2.getScrollX(), layout2.getScrollY(), -200, 0);

       handler.sendEmptyMessage(FLUSH);

      这时候就需要看看Scroller这个类,它就类似一个计算中心,通常是用Scroller对象记录或计算View滚动的位置,当我们点击Button的时候,Scroller调用startScroll方法,这个方法中的四个参数分别是基准点位置及偏移量,这个方法里只是记录了这些参数,

    public void startScroll(int scrollX, int scrollY, int distanceX, int distanceY) {

    startX = scrollX;

    startY = scrollY;

    this.distanceX = distanceX;

    this.distanceY = distanceY;

    isFinish = false;

    startTime = SystemClock.uptimeMillis();

       }

      然后再发送handler信息,handler里先判断scroller.computeScrollOffset(),这个返回true时表示还在移动,

    /**

     * 计算偏移量,这个方法得出当前执行到哪个位置了

     * @return true 还在移动  false:移动已经停止,duration = 1000l

     */

    public boolean computeScrollOffset() {

    if (isFinish) {

    return false;

    }

    long timePassed = SystemClock.uptimeMillis()- startTime;

    if (timePassed < duration) {

    currentX = (int) (startX + distanceX  * timePassed / duration);

    currentY = (int) (startY + distanceY * timePassed/ duration );

    System.out.println("currentX:::" + currentX);

    } else if (timePassed >= duration) {

    currentX = startX + distanceX;

    currentY = startY + distanceY;

    isFinish = true;

    }

    return true;

       }

      

      定义的handler

    private Handler handler = new Handler(){

    @Override

    public void handleMessage(Message msg) {

    if(msg.what == FLUSH){

    if(scroller.computeScrollOffset()){

    layout2.scrollTo(scroller.getCurrX(), 0);

    handler.sendEmptyMessage(FLUSH);

    }

    }

    }

    };

    Le王冬冬 博客分享地址: http://www.cnblogs.com/dongdong230/ 每个人都应做一天攻城狮
  • 相关阅读:
    Freedur为什么会免费?
    Cocos2d-x中使用音频CocosDenshion引擎介绍与音频文件的预处理
    AssetManager asset的使用
    Android AsyncHttpClient
    UI标签库专题十三:JEECG智能开发平台 ckfinder(ckfinder插件标签)
    UBUNTU 下如何升级 gcc, g++
    java 泛型深入之Set有用工具 各种集合泛型深入使用演示样例,匿名内部类、内部类应用于泛型探讨
    最新Connectify注冊码(序列号) Connectify3.7序列号 破解版
    简单单元測试思想
    Dijkstra算法
  • 原文地址:https://www.cnblogs.com/dongdong230/p/4183045.html
Copyright © 2011-2022 走看看