返回介绍

5.2 createViewFromTag 方法解析

发布于 2024-12-23 22:04:07 字数 3131 浏览 0 评论 0 收藏 0

createViewFromTag 方法主要通过要实例化 View 的父 View、要实例化 View 的名称、Context 上下文、属性值来实例化 View。该方法主要做的操作有:

  1. 先尝试用用户设置的 Factory 以及自己私有的 Factory 来实例化 View。
  2. 如果这几个 Factory 都没有实例化 View,则调用 onCreateView 或者 createView 来实例化 View。

代码分析:

/*
 * 缺省方法可见性,好让 BridgeInflater 能重写它。
 * 根据父 View、View 名称、Context、属性实例化 View。
 */
private View createViewFromTag(View parent, String name, Context context, AttributeSet attrs) {
  return createViewFromTag(parent, name, context, attrs, false);
}

View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,
    boolean ignoreThemeAttr) {

	// 如果是 View 标签,则用 class 指向的类的完整名称来替换当前名称。(我们都知道,用 Fragment 的时候,可指定 class="Fragment 完整路径名",其他 widget 控件也类似)
  if (name.equals("view")) {
    name = attrs.getAttributeValue(null, "class");
  }

	// 应用主题包装,如果允许并且已经被指定
  // Apply a theme wrapper, if allowed and one is specified.
  if (!ignoreThemeAttr) {
		// 获取 Context 中主题属性
    final TypedArray ta = context.obtainStyledAttributes(attrs, ATTRS_THEME);
    final int themeResId = ta.getResourceId(0, 0);
		// 如果包含了主题,则用 ContextThemeWrapper 包装一下
    if (themeResId != 0) {
      context = new ContextThemeWrapper(context, themeResId);
    }
    ta.recycle();
  }
	
	// 如果根标签是“1995”,则创建一个“BlinkLayout”(其实就是一个 FrameLayout)
	// ps:这个没见过在哪里用到过。
  if (name.equals(TAG_1995)) {
    // Let's party like it's 1995!
    return new BlinkLayout(context, attrs);
  }

  try {
    View view;
		// 尝试通过 mFactory2 或者 mFactory 来创建 View,这两个是通过 setFactory 和 setFactory2 来设置的。
    if (mFactory2 != null) {
      view = mFactory2.onCreateView(parent, name, context, attrs);
    } else if (mFactory != null) {
      view = mFactory.onCreateView(name, context, attrs);
    } else {
      view = null;
    }

		// 如果没有设置自定义工厂并且 LayoutInflater 本身私有的 View 工厂不为空,则用私有 View 工厂创建 View。
    if (view == null && mPrivateFactory != null) {
      view = mPrivateFactory.onCreateView(parent, name, context, attrs);
    }

		// 如果 View 还为空,也即没有工厂,或者工厂未能正确创建 View,则尝试通过自身的方法实例化 View
    if (view == null) {
      final Object lastContext = mConstructorArgs[0];
      mConstructorArgs[0] = context;
      try {
        if (-1 == name.indexOf('.')) {

					// 如果 View 标签中没有".",则代表是系统的 widget,则调用 onCreateView,这个方法会通过"createView"方法创建 View
					// 不过前缀字段会自动补"android.view."。
          view = onCreateView(parent, name, attrs);
        } else {

					// 非系统控件,则 name 本身就是控件的完整路径名。
					//通过 widget 完整路径名以及属性创建 View。
          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);
    ie.initCause(e);
    throw ie;

  } catch (Exception e) {
    final InflateException ie = new InflateException(attrs.getPositionDescription()
        + ": Error inflating class " + name);
    ie.initCause(e);
    throw ie;
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文