微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

android – 将子视图从XML添加到Layout / ViewGroup时

我的问题是:
我想知道xLayout(或一般来说是ViewGroup)什么时候从 XML添加子视图? “何时”我的意思是什么代码,什么“通过”UI工具包的“遍历”?
应该覆盖哪个xLayout或ViewGroup的方法

我已经完成了我的功课:我看过“Writing Custom Views For Android”在最近的Google I / O中提交的(Adam Powell和Romain Guy),并且已经阅读了Adam Powell在Google post上的评论.

解决方法

Looking for the exact point in Android’s source code where children are added.

我们可以看看setContentView(R.layout.some_id)正在做什么.

setContentView(int)调用PhoneWindow#setContentView(int) – PhoneWindowLink是Window的具体实现:

@Override
public void setContentView(int layoutResID) {
    if (mContentParent == null) {
        installDecor();
    } else {
        mContentParent.removeAllViews();
    }
    mLayoutInflater.inflate(layoutResID,mContentParent);
    final Callback cb = getCallback();
    if (cb != null && !isDestroyed()) {
        cb.onContentChanged();
    }
}

方法LayoutInflater#inflate(layoutResID,mContentParent)最终在mContentParent上调用ViewGroup#addView(View,LayoutParams).之间,儿童视图

I want to kNow what happens exactly after I set content view to an XML file that contains a custom view. Afer the constructor there has to be a part in the code where the custom view “parse/read/inflate/convert” XML-declared child views to actual views ! (comment by JohnTube)

Ambiquity:从JohnTube的评论来看,他似乎更有兴趣了解自定义视图是如何膨胀的.要知道这一点,我们将看看LayoutInflaterLink的工作原理.

那么,我应该覆盖哪个xLayout或ViewGroup的方法的答案?是ViewGroup#addView(View,LayoutParams).请注意,在这一点上,所有常规/定制视图的通货膨胀已经发生.

自订视图通货膨胀:

LayoutInflater中的以下方法是在父/ root上调用addView(View,LayoutParams)的位置:

注意:调用mLayoutInflater.inflate(layoutResID,mContentParent);在PhoneWindow#setContentView(int)中链接到这个.这里的mContentParent是DecorView:可以通过getwindow()访问的视图getDecorView().

// Inflate a new view hierarchy from the specified XML node.
public View inflate(XmlPullParser parser,ViewGroup root,boolean attachToRoot)

// Recursive method used to descend down the xml hierarchy and instantiate views,// instantiate their children,and then call onFinishInflate().
void rInflate(XmlPullParser parser,View parent,final AttributeSet attrs,boolean finishInflate) throws XmlPullParserException,IOException

方法的兴趣调用(和递归rInflate(XmlPullParser,View,AttributeSet,boolean))是:

temp = createViewFromTag(root,name,attrs);

看看createViewFromTag(…)正在做什么:

View createViewFromTag(View parent,String name,AttributeSet attrs) {
    ....
    ....
    if (view == null) {
        if (-1 == name.indexOf('.')) {
            view = onCreateView(parent,attrs);
        } else {
            view = createView(name,null,attrs);
        }
    }
    ....
}

句点(.)决定是否调用了onCreateView(…)或createView(…).

为什么这个检查?因为在android.view,android.widget或android.webkit包中定义的视图是通过其类名来访问的.例如:

android.widget: Button,TextView etc.

android.view: ViewStub. SurfaceView,TextureView etc.

android.webkit: WebView

遇到这些视图时,会调用onCreateView(parent,attrs).这个方法实际上链接到createView(…):

protected View onCreateView(String name,AttributeSet attrs) throws ClassNotFoundException {
    return createView(name,"android.view.",attrs);
}

这将处理在Android.view包中定义的SurfaceView,TextureView和其他视图.如果您有兴趣了解TextView,Button等如何处理,请查看PhoneLayoutInflaterLink – 它扩展了LayoutInflater并覆盖onCreateView(…),以检查android.widget和android.webkit是否是预期的包名称.其实调用getLayoutInflater()可以得到一个PhoneLayoutInflater的实例.这就是为什么如果你要布局LayoutInflater,你甚至不能夸大最简单的布局 – 因为LayoutInflater只能处理来自android.view包的视图.

无论如何,我离题.这个额外的位发生在常规视图中 – 在它们的定义中没有句点(.).自定义视图在其名称中有一段时间 – com.my.package.CustomView.这是LayoutInflater如何区分两者.

所以,在常规视图(比如说Button)的情况下,前缀如android.widget将作为第二个参数传递 – 对于自定义视图,这将为null.然后将该前缀与名称一起使用以获取该特定视图的类的构造函数.自定义视图不需要此,因为它们的名称已经完全限定.我想这是为了方便而做的.否则,您将以这种方式定义您的布局:

<android.widget.LinearLayout
    ...
    ... />

(它的法律虽然…)

此外,这就是为什么来自支持库(例如< android.support.v4.widget.DrawerLayout ... />)的视图必须使用完全限定名称的原因.

顺便说一句,如果你确实想要把你的布局写成:

<MyCustomView ../>

所有你需要做的是扩展LayoutInflater并添加你的包名com.my.package.到通货膨胀期间检查的字符串列表.检查PhoneLayoutInflater以获得帮助.

让我们看看在最后阶段对于自定义和常规视图会发生什么 – createView(…):

public final View createView(String name,String prefix,AttributeSet attrs)
                            throws ClassNotFoundException,InflateException {

    // Try looking for the constructor in cache
    Constructor<? extends View> constructor = sConstructorMap.get(name);
    Class<? extends View> clazz = null;

    try {
        if (constructor == null) {
            // Class not found in the cache,see if it's real,and try to add it
            clazz = mContext.getClassLoader().loadClass(
                 prefix != null ? (prefix + name) : name).asSubclass(View.class);
            ....
            // Get constructor   
            constructor = clazz.getConstructor(mConstructorSignature);
            sConstructorMap.put(name,constructor);
        } else {
            ....
        }

        Object[] args = mConstructorArgs;
        args[1] = attrs;

        // Obtain an instance
        final View view = constructor.newInstance(args);
        ....

        // We finally have a view!
        return view;
    }
    // A bunch of catch blocks: 
        - if the only constructor defined is `CustomView(Context)` - NoSuchMethodException
        - if `com.my.package.CustomView` doesn't extend View - ClassCastException
        - if `com.my.package.CustomView` is not found - ClassNotFoundException

    // All these catch blocks throw the often seen `InflateException`.
}

一个视图诞生了.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐