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) //实现滚动和特效显示 ......其他函数,实现特效处理效果或者具体的计算操作。 } |
android 的核心 ViewGroup
最新推荐文章于 2023-08-22 15:16:16 发布