一起Talk Android吧(第一百四十四回:Android自定义View之Layout一)

各位看官们大家好,上一回中咱们说的是Android中自定义View之Measure的例子,这一回咱们说的例子是自定义View之Layout。闲话休提,言归正转。让我们一起Talk Android吧!

看官们,我们在前面章回中介绍了Measure的细节和流程,在接下来的章回中将介绍Layout的细节和流程,其实我们在前面章回中介绍过Layout的流程,在这里我们对其做进一步的完善:

    doTraversal()->performTraversals()->performLayout()->layout()->onLayout()

该流程中前三个函数在ViewRootImpl.java文件中,后两个函数在View.java文件中(这点和Measure流程一样)。明白流程后我们重点看看layout的源代码,具体如下:

 public void layout(int l, int t, int r, int b) {
     if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) {
         onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec);
         mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
     }

     int oldL = mLeft;
     int oldT = mTop;
     int oldB = mBottom;
     int oldR = mRight;

     boolean changed = isLayoutModeOptical(mParent) ?
             setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);

     if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
         onLayout(changed, l, t, r, b);

         if (shouldDrawRoundScrollbar()) {
             if(mRoundScrollbarRenderer == null) {
                 mRoundScrollbarRenderer = new RoundScrollbarRenderer(this);
             }
         } else {
             mRoundScrollbarRenderer = null;
         }

         mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;

         ListenerInfo li = mListenerInfo;
         if (li != null && li.mOnLayoutChangeListeners != null) {
             ArrayList<OnLayoutChangeListener> listenersCopy =
                     (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone();
             int numListeners = listenersCopy.size();
             for (int i = 0; i < numListeners; ++i) {
                 listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB);
             }
         }
     }

     final boolean wasLayoutValid = isLayoutValid();

     mPrivateFlags &= ~PFLAG_FORCE_LAYOUT;
     mPrivateFlags3 |= PFLAG3_IS_LAID_OUT;

     if (!wasLayoutValid && isFocused()) {
         mPrivateFlags &= ~PFLAG_WANTS_FOCUS;
         if (canTakeFocus()) {
             // We have a robust focus, so parents should no longer be wanting focus.
             clearParentsWantFocus();
         } else if (getViewRootImpl() == null || !getViewRootImpl().isInLayout()) {
             // This is a weird case. Most-likely the user, rather than ViewRootImpl, called
             // layout. In this case, there's no guarantee that parent layouts will be evaluated
             // and thus the safest action is to clear focus here.
             clearFocusInternal(null, /* propagate */ true, /* refocus */ false);
             clearParentsWantFocus();
         } else if (!hasParentWantsFocus()) {
             // original requestFocus was likely on this view directly, so just clear focus
             clearFocusInternal(null, /* propagate */ true, /* refocus */ false);
         }
         // otherwise, we let parents handle re-assigning focus during their layout passes.
     } else if ((mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) {
         mPrivateFlags &= ~PFLAG_WANTS_FOCUS;
         View focused = findFocus();
         if (focused != null) {
             // Try to restore focus as close as possible to our starting focus.
             if (!restoreDefaultFocus() && !hasParentWantsFocus()) {
                 // Give up and clear focus once we've reached the top-most parent which wants
                 // focus.
                 focused.clearFocusInternal(null, /* propagate */ true, /* refocus */ false);
             }
         }
     }

     if ((mPrivateFlags3 & PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT) != 0) {
         mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT;
         notifyEnterOrExitForAutoFillIfNeeded(true);
     }
 }

从上面的代码中可以看出layout首先通过setFrame()方法确定自己的位置,也就是我们前面章回中介绍过的View的坐标,然后调用onLayout()方法去确定子View的位置。不过onLayout()方法是空的,View类没有实现,而是把它留给了子类去实现。

各位看官,关于Androd中自定义View之Layout的例子咱们就介绍到这里,欲知后面还有什么例子,且听下回分解!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

talk_8

真诚赞赏,手有余香

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值