zoukankan      html  css  js  c++  java
  • 认识setFactory

    平常设置或者获取一个View时,用的较多的是setContentView或LayoutInflater#inflate,setContentView内部也是通过调用LayoutInflater#inflate实现(具体调用在AppCompatViewInflater#setContentView(ind resId)中)。

    通过LayoutInflater#inflate可以将xml布局文件解析为所需要的View,通过分析LayoutInflate#inflate源码,可以看到.xml布局文件在解析的过程中会调用LayoutInflater#rInflate,随后会通过调用LayoutInflater#createViewFromTag来创建View。这里推荐《遇见LayoutInflater&Factory》
    下面一起看看View的创建过程LayoutInflate#createViewFormTag:

    View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,
    boolean ignoreThemeAttr) {
    if (name.equals("view")) {
    name = attrs.getAttributeValue(null, "class");
    }

    // Apply a theme wrapper, if allowed and one is specified.
    if (!ignoreThemeAttr) {
    final TypedArray ta = context.obtainStyledAttributes(attrs, ATTRS_THEME);
    final int themeResId = ta.getResourceId(0, 0);
    if (themeResId != 0) {
    context = new ContextThemeWrapper(context, themeResId);
    }
    ta.recycle();
    }

    if (name.equals(TAG_1995)) {
    // Let's party like it's 1995!
    return new BlinkLayout(context, attrs);
    }

    try {
    View view;
    if (mFactory2 != null) {
    //根据attrs信息,通过mFactory2创建View
    view = mFactory2.onCreateView(parent, name, context, attrs);
    } else if (mFactory != null) {
    //根据attrs信息,通过mFactory创建View
    view = mFactory.onCreateView(name, context, attrs);
    } else {
    view = null;
    }

    if (view == null && mPrivateFactory != null) {
    view = mPrivateFactory.onCreateView(parent, name, context, attrs);
    }

    if (view == null) {
    final Object lastContext = mConstructorArgs[0];
    mConstructorArgs[0] = context;
    try {
    if (-1 == name.indexOf('.')) {
    //创建Android原生的View(android.view包下面的view)
    view = onCreateView(parent, name, attrs);
    } else {
    //创建自定义View或者依赖包中的View(xml中声明的是全路径)
    view = createView(name, null, attrs);
    }
    } finally {
    mConstructorArgs[0] = lastContext;
    }
    }

    return view;
    } catch (InflateException e) {
    throw e;

    } catch (ClassNotFoundException e) {
    final InflateException ie = new InflateException(attrs.getPositionDescription()
    + ": Error inflating class " + name, e);
    ie.setStackTrace(EMPTY_STACK_TRACE);
    throw ie;

    } catch (Exception e) {
    final InflateException ie = new InflateException(attrs.getPositionDescription()
    + ": Error inflating class " + name, e);
    ie.setStackTrace(EMPTY_STACK_TRACE);
    throw ie;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    从上述源码中可以看出View的创建过程中,会首先找Factory2#onCreateView和Factory#onCreateView进行创建,然后走默认的创建流程。所以,我们可以在此处创建自定义的Factory2或Factory,并将自定义的Factory2或Factory对象添加到LayoutInflater对象当中,来对View的创建进行干预,LayoutInflate也提供了相关的API供我们添加自己的ViewFactory。

    例如:下面我们通过设置LayoutInflater的Factory来,将视图中的Button转换为TextView

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
    LayoutInflater.from(this).setFactory(new LayoutInflater.Factory() {
    @Override
    public View onCreateView(String name, Context context, AttributeSet attrs) {
    for (int i = 0; i < attrs.getAttributeCount(); i ++){
    String attrName = attrs.getAttributeName(i);
    String attrValue = attrs.getAttributeValue(i);
    Log.i(TAG, String.format("name = %s, attrName = %s, attrValue= %s", name, attrName, attrValue));
    }
    TextView textView = null;
    if (name.equals("Button")){
    textView = new TextView(context, attrs);
    }

    return textView;
    }
    });
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_theme_change);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    让后启动Activity后,视图中的Button都转化成了TextView,并且能看到输出:

    name = Button, attrName = id, attrValue= @2131230758
    name = Button, attrName = background, attrValue= @2131034152
    name = Button, attrName = layout_width, attrValue= -2
    name = Button, attrName = layout_height, attrValue= -2
    name = Button, attrName = id, attrValue= @2131230757
    name = Button, attrName = background, attrValue= @2131034150
    name = Button, attrName = layout_width, attrValue= -2
    name = Button, attrName = layout_height, attrValue= -2
    1
    2
    3
    4
    5
    6
    7
    8
    获取任意一个apk压缩文件的Resource对象
    上述过程已经提供了更改View类型以及属性的方式,下面我们见介绍如何获取一个apk压缩文件中的res资源。

    我们通常通过Context#getSource()获取res目录下的资源,Context#getAssets()(想当于Context#getSource().getAssets())获取asset目录下的资源。所以要获取一个apk压缩文件的资源文件,创建对应该压缩文件的Resource实例,然后通过这个实例获取压缩文件中的资源信息。
    比如,新创建的的Resource实例为mResource,则可以使用mResource.getColor(colorId),来获取实例内colorId所对应的颜色。

    那么接下来的问题分为两步:
    --------------------- 

  • 相关阅读:
    [备忘]使用Outlook 2010,拖拽大于20M附件发生“附件大小超过了允许的范围”提示的解决方法
    关于Linq to SQL 的“异常详细信息: System.InvalidCastException: 指定的转换无效。”
    [备忘]ie6中href设为javascript:void(0)页面无法提交的解决方法
    [备忘]谷歌员工证实PR值不再更新 呼吁用户关注内容
    今天早上
    C++primer6.20
    Fuzzy KNN
    数值转换
    ArcMap分割图斑
    VS2008 集成openCV过程
  • 原文地址:https://www.cnblogs.com/ly570/p/11284690.html
Copyright © 2011-2022 走看看