android 的核心 ViewGroup

android 的核心 ViewGroup

一、机制描述:
       我前面的博客简单的学习了VIEW级特殊View的介绍,但是,在平常更普通的应用中,更加讲究的如何更换VIEW的特效处理,如何将多个View放在一个Activity中(让其具有多页滚动效果),如何动态和加载layout,这些我们都需要从View的管理机制中获得。      先简单的描述下类及功能,还有在framework中的架构,然后重点阅读ViewGroup类。
      1、ViewGroup是一个View类的子类,但是其负担着View本身的管理,View是一组绘制的图形,这组图形能够接受用户传递过来的事件,同时这组图形还能进行平移,旋转,缩放等显示特效,各种不同的view通过ViewManager的加,删,更新等操作显示在界面上,在View的管理中,操作系统的本身消息机制负责管理绘制的消息传递,最后通过rootview的操作完成绘制。ViewGroup的具体函数功能,实现了ViewManager的所有功能,另外其还实现了ViewParent类的功能(该类完成了View的更新,重画,布局等功能),另外,该类还是实现了View焦点操作,View的事件传递,绘制,拖动处理,特效动画。
      2、 ViewGroup提供了OnMeasure和 OnLayout的操作功能,通过这两个功能或者类似的操作函数来完成具体的view大小更改和布局。
      3、日常应用的各种layout类都继承viewgroup,比如LinearLayout, FrameLayout,AbsoluteLayout,RelativeLayout等,这些layout在XML文件中定义,然后被程序定义和使用,完成各种形式的布局,最后程序通过调用setcontview或者inflate完成在屏幕上的实现功能。
      4、在后续的应用中,android 4.0后提供的pageview之类的类,也是继承ViewGroup,实现多页面的管理,launcher的多页面操作可以使用pageview完成。

二 ViewGroup代码:
现在我们具体看看ViewGroup代码中的功能,
       public abstract class ViewGroup extends View implements ViewParent, ViewManager   //本身是View类,实现了接口类ViewParent和ViewManager
       {
           protected ArrayList<View> mDisappearingChildren;      //让孩子可见或者不可见
           protected OnHierarchyChangeListener mOnHierarchyChangeListener;  //监听事件
           private View mFocused;               //当前聚焦的view
           private final Transformation mChildTransformation = new Transformation(); //绘制参数
           private RectF mInvalidateRegion;        //有效区域
           private Transformation mInvalidationTransformation; //有效区域的参数
           private View mCurrentDragView;        //当前拖动的view
           private DragEvent mCurrentDrag;  //拖动的事件
           private HashSet<View> mDragNotifiedChildren; //拖动事件可以传递给哪些view集合
           private boolean mChildAcceptsDrag;  //能否接受拖动
           private final PointF mLocalPoint = new PointF(); //拖动中的控制点
           private LayoutAnimationController mLayoutAnimationController;   //layout动画特效控制
           private Animation.AnimationListener mAnimationListener;     //特效动画控制监听
           private TouchTarget mFirstTouchTarget;    //第一个触摸目标
           private HoverTarget mFirstHoverTarget;   //第一个Hover目标
           private Paint mCachePaint;   //画板
           private LayoutTransition mTransition;  //layout时的动画特效
           private ArrayList<View> mTransitioningViews;  //变换动画特效的view
           private ArrayList<View> mVisibilityChangingChildren; //可视的view
           .....(view的构造函数等,不介绍)
           public int getDescendantFocusability()    //后代view的焦点,焦点是接受事件的关键,那么多view,谁接受鼠标事件,谁接受按键事件,就看是否是焦点
           public void requestChildFocus(View child, View focused)  //请求孩子聚焦
           public void focusableViewAvailable(View v)  //孩子能否聚焦
           public View focusSearch(View focused, int direction)  //搜索可以作为焦点的孩子
           public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate)   //判断孩子是否在某个区域
           public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) //孩子能否接受事件
           public boolean dispatchUnhandledMove(View focused, int direction)   //传输焦点事件
           public void clearChildFocus(View child)    //清除孩子的焦点
           public View getFocusedChild()   //得到当前获得焦点的view
           public void addFocusables(ArrayList<View> views, int direction, int focusableMode)  //加焦点
           public void findViewsWithText(ArrayList<View> outViews, CharSequence text, int flags) //根据文本标示获得view
           View findViewByAccessibilityIdTraversal(int accessibilityId)  //根据 accessibilityId找到对应的view
           public void dispatchWindowFocusChanged(boolean hasFocus) //处理焦点改变的窗口消息
           protected void onChildVisibilityChanged(View child, int visibility)  //当子view可见或者不可见的时候激活事件
           public void dispatchWindowVisibilityChanged(int visibility)   //处理可见不可见改变事件
           public void bringChildToFront(View child)  //将孩子向前移动,
           public boolean dispatchDragEvent(DragEvent event)  //拖动事件消息处理
           boolean notifyChildOfDrag(View child)  //提示孩子拖动
           public void dispatchSystemUiVisibilityChanged(int visible)   //处理systemui可见不可见改变
           public boolean dispatchKeyEventPreIme(KeyEvent event) //处理输入法按键事件
           public boolean dispatchKeyEvent(KeyEvent event) //处理按键事件
           public boolean dispatchKeyShortcutEvent(KeyEvent event) //处理shortcut事件
           public boolean dispatchTrackballEvent(MotionEvent event)  //处理鼠标或者轨迹球事件
           protected boolean dispatchHoverEvent(MotionEvent event) //处理Hover事件
           public boolean dispatchTouchEvent(MotionEvent ev)  //处理触摸事件、
           private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel, View child, int desiredPointerIdBits)  //  处理触摸变换事件
           public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) //请求是否允许拦截触摸事件
           protected void setChildrenDrawingCacheEnabled(boolean enabled)  //是否允许子view建立cache buffer
           protected void onAnimationStart()   //动画启动
           Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren)  //建立一个快照
           protected void dispatchDraw(Canvas canvas)  //处理ViewGroup的绘制操作
           protected boolean drawChild(Canvas canvas, View child, long drawingTime) //上面函数调用的绘制子函数
           public void addView(View child)  // ViewManager的接口实现类
           public void updateViewLayout(View view, ViewGroup.LayoutParams params)  //更新layout
           public final void invalidateChild(View child, final Rect dirty)  //重新绘制子VIEW
           protected abstract void onLayout(boolean changed,  int l, int t, int r, int b);  //需要用户实现的layout操作,用户实现该函数后,view可以布局在屏幕上
           protected abstract void onMeasure(boolean changed,  int width,int height);  //需要用户实现的Measure操作,用户实现该函数后,view可以在屏幕上实现大小的变化

           ......具体代码中有如何实现子view的特效处理,也有具体的布局操作,也有子view 的具体绘制操作。
       }
三、应用实例:
      以launcher为例:
      laucher是android的待机画面,PageView从ViewGroup继承而来,实现了多个页面,每一页占据整个屏幕,实现上将多页”拼凑“在一张虚拟的大图上,每页中包含各种不同的View(如图表,文字,系统状态条),通过用户的手势滑动操作完成拖动的特效处理,拖动后切换页面的处理。下面列出其重点函数进行简单介绍:
     public abstract class PagedView extends ViewGroup {
                 void setCurrentPage(int currentPage)   //page view是按页显示的,设置为那一页,就有相关的切换操作,如scrollTo,invalidate();
                 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)  //对每个页面进行量尺寸
                  {
                        final int childCount = getChildCount();
                        for (int i = 0; i < childCount; i++) {
                                final View child = getPageAt(i);
                                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
                                int childWidthMode;
                                if (lp.width == LayoutParams.WRAP_CONTENT) {
                                       childWidthMode = MeasureSpec.AT_MOST;
                               } else {
                                       childWidthMode = MeasureSpec.EXACTLY;
                               }

                               int childHeightMode;
                               if (lp.height == LayoutParams.WRAP_CONTENT) {
                                         childHeightMode = MeasureSpec.AT_MOST;
                                } else {
                                         childHeightMode = MeasureSpec.EXACTLY;
                                }

                               final int childWidthMeasureSpec =  MeasureSpec.makeMeasureSpec(widthSize - horizontalPadding, childWidthMode);
                               final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize - verticalPadding, childHeightMode);
                               child.measure(childWidthMeasureSpec, childHeightMeasureSpec);     //去掉padding的真实宽和高
                               maxChildHeight = Math.max(maxChildHeight, child.getMeasuredHeight());
                  }

                  protected void onLayout(boolean changed, int left, int top, int right, int bottom) {   //放在大图上面,然后通过滚动操作完成不同页面的显示                       if (!mIsDataReady) {
                           return;
                      }

                      if (DEBUG) Log.d(TAG, "PagedView.onLayout()");
                      final int verticalPadding = mPaddingTop + mPaddingBottom;
                      final int childCount = getChildCount();
                      int childLeft = 0;
                      if (childCount > 0) {
                            childLeft = getRelativeChildOffset(0);
                           // Calculate the variable page spacing if necessary
                           if (mPageSpacing < 0) {
                               setPageSpacing(((right - left) - getChildAt(0).getMeasuredWidth()) / 2);
                          }
                    }

                   for (int i = 0; i < childCount; i++) {
                      final View child = getPageAt(i);
                      if (child.getVisibility() != View.GONE) {
                           final int childWidth = getScaledMeasuredWidth(child);
                           final int childHeight = child.getMeasuredHeight();
                           int childTop = mPaddingTop;
                           if (mCenterPagesVertically) {
                                childTop += ((getMeasuredHeight() - verticalPadding) - childHeight) / 2;
                           }

                         child.layout(childLeft, childTop,  childLeft + child.getMeasuredWidth(), childTop + childHeight);    //page view 左右或者上下layout到一张大图上,方便滚动操作
                         childLeft += childWidth + mPageSpacing * 2;
                }
           }

           if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) {      //设置滚动特性
                      setHorizontalScrollBarEnabled(false);
                      int newX = getChildOffset(mCurrentPage) - getRelativeChildOffset(mCurrentPage);
                      scrollTo(newX, 0);
                      mScroller.setFinalX(newX);
                      setHorizontalScrollBarEnabled(true);
                     mFirstLayout = false;
            }

          if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) {
                      mFirstLayout = false;
           }
        }

         protected void dispatchDraw(Canvas canvas)    //该函数实现了drawchild的功能
         public boolean onInterceptTouchEvent(MotionEvent ev)  //截获Touch事件,进行特效效果显示
         public boolean onTouchEvent(MotionEvent ev)   //实现滚动和特效显示
         ......其他函数,实现特效处理效果或者具体的计算操作。
     }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值