安卓View开发心得(三)

onLayout (boolean changed, int left,int top,int right,int bottom)
Called from layout when this view should assign a size and position to each of its children. Derived classes with children should override this method and call layout on each of their children.
layout (int l, int t, int r, int b)
Assign a size and position to a view and all of its descendants
This is the second phase of the layout mechanism. (The first is measuring). In this phase, each parent calls layout on all of its children to position them. This is typically done using the child measurements that were stored in the measure pass().
Derived classes should not override this method. Derived classes with children should override onLayout. In that method, they should call layout on each of their children.
先看看View的layout/onLayout:layout()非final,意味着子类是可以随便重写,在方法中调用自身的onLayout()。onLayout()是一个空方法,没有做任何事情。再看ViewGroup:
@Override
public final void layout(int l, int t, int r, int b) {
    if (!mSuppressLayout && (mTransition == null || !mTransition.isChangingLayout())) {
        if (mTransition != null) {
            mTransition.layoutChange(this);
        }
        super.layout(l, t, r, b);
    } else {
        // record the fact that we noop'd it; request layout when transition finishes
        mLayoutCalledWhileSuppressed = true;
    }
}
@Override
protected abstract void onLayout(boolean changed,
        int l, int t, int r, int b);
ViewGroup的layout调用了父类的layout,onLayout则直接定义成了抽象方法,要求ViewGroup的子类必须实现onLayout,以对child view进行layout。从RelativeLayout.onLayout()可以看到对child view的layout操作:
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    //  The layout has actually already been performed and the positions
    //  cached.  Apply the cached values to the children.
    final int count = getChildCount();

    for (int i = 0; i < count; i++) {
        View child = getChildAt(i);
        if (child.getVisibility() != GONE) {
            RelativeLayout.LayoutParams st =
                    (RelativeLayout.LayoutParams) child.getLayoutParams();
            child.layout(st.mLeft, st.mTop, st.mRight, st.mBottom);
        }
    }
}
所以,parent view和child view的layout过程的迭代调用关系同measure。
总结下来,关于在自己开发的View中使用onLayout()需要注意:
(1)自定义的ViewGroup,需要实现onLayout,并且必须在其中对child view进行layout。

void onDraw (Canvas canvas)
Implement this to do your drawing.
void draw (Canvas canvas)
Manually render this view (and all of its children) to the given Canvas. The view must have already done a full layout before this function is called. When implementing a view, implement onDraw(android.graphics.Canvas) instead of overriding this method. If you do need to override this method, call the superclass version.
第三阶段draw,从官方文档可以看到,虽然View.draw()方法没有设计成final,即给继承者留下了重写的空间,但明确要求必须手动调用super.draw()。将扩展性放到了onDraw中。View.onDraw()没有做任何事。
再看看TextView,没有重写draw(),但onDraw()比较复杂,约170行。ViewGroup/RelativeLayout都没有重写draw()和onDraw()。
draw涉及到View的一个概念:drawing order(z order)。视觉效果上,child view在parent view的前面(上面)显示;在一个RelativeLayout中,同样位置位于更后面定义的chid view显示在前面(上面),都与z order有关。通过接口setZ(float)可以修改z order。
总结下来,关于在自己开发的View中使用onDraw()需要注意:
(1)与measure和layout相比较,draw更关注于View的展示内容,所以在动画的处理上,onDraw的使用更多。
(2)对于ViewGroup,并不需要在onDraw中处理child view的draw相关的逻辑,onDraw只需要关注自身的绘制。

如上,三个过程都写完了,那么,除了手动调用measure()/layout()/draw(),还有什么办法可以手动触发View的生命周期呢?安卓提供如下api:
(1)requestLayout():触发measure-layout。
(2)invalidate():强制draw。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值