6:LayoutInflater、Factory(小红书引导页)

1、LayoutInflater源码解析

  • LayoutInflater#inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot)

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

创建View方式:首先通过mFactory、mFactory等,如果其都为null,则通过name反射创建View。

    public interface Factory {
        /**
         * Hook you can supply that is called when inflating from a LayoutInflater.
         * You can use this to customize the tag names available in your XML
         * layout files.
         *
         * <p>
         * Note that it is good practice to prefix these custom names with your
         * package (i.e., com.coolcompany.apps) to avoid conflicts with system
         * names.
         *
         * @param name Tag name to be inflated.
         * @param context The context the view is being created in.
         * @param attrs Inflation attributes as specified in XML file.
         *
         * @return View Newly created view. Return null for the default
         *         behavior.
         */
        public View onCreateView(String name, Context context, AttributeSet attrs);
    }

    public interface Factory2 extends Factory {
        /**
         * Version of {@link #onCreateView(String, Context, AttributeSet)}
         * that also supplies the parent that the view created view will be
         * placed in.
         *
         * @param parent The parent that the created view will be placed
         * in; <em>note that this may be null</em>.
         * @param name Tag name to be inflated.
         * @param context The context the view is being created in.
         * @param attrs Inflation attributes as specified in XML file.
         *
         * @return View Newly created view. Return null for the default
         *         behavior.
         */
        public View onCreateView(View parent, String name, Context context, AttributeSet attrs);
    }
复制代码

自定义LayoutInflater,即通过实现Factory2在自定义的tag填充过程中执行自己的一些操作。 而由于LayoutInflater是系统服务,且是单例,因此需要通过LayoutInflater#cloneInContext克隆出一个实例,再setFactory。

  • rInflateChildren
    /**
     * Recursive method used to inflate internal (non-root) children. This
     * method calls through to {@link #rInflate} using the parent context as
     * the inflation context.
     * <strong>Note:</strong> Default visibility so the BridgeInflater can
     * call it.
     */
    final void rInflateChildren(XmlPullParser parser, View parent, AttributeSet attrs,
            boolean finishInflate) throws XmlPullParserException, IOException {
        rInflate(parser, parent, parent.getContext(), attrs, finishInflate);
    }

    /**
     * Recursive method used to descend down the xml hierarchy and instantiate
     * views, instantiate their children, and then call onFinishInflate().
     * <p>
     * <strong>Note:</strong> Default visibility so the BridgeInflater can
     * override it.
     */
    void rInflate(XmlPullParser parser, View parent, Context context,
            AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException {

        final int depth = parser.getDepth();
        int type;
        boolean pendingRequestFocus = false;

        while (((type = parser.next()) != XmlPullParser.END_TAG ||
                parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {

            if (type != XmlPullParser.START_TAG) {
                continue;
            }

            final String name = parser.getName();

            if (TAG_REQUEST_FOCUS.equals(name)) {
                pendingRequestFocus = true;
                consumeChildElements(parser);
            } else if (TAG_TAG.equals(name)) {
                parseViewTag(parser, parent, attrs);
            } else if (TAG_INCLUDE.equals(name)) {
                if (parser.getDepth() == 0) {
                    throw new InflateException("<include /> cannot be the root element");
                }
                parseInclude(parser, context, parent, attrs);
            } else if (TAG_MERGE.equals(name)) {
                throw new InflateException("<merge /> must be the root element");
            } else {
                final View view = createViewFromTag(parent, name, context, attrs);
                final ViewGroup viewGroup = (ViewGroup) parent;
                final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
                rInflateChildren(parser, view, attrs, true);
                viewGroup.addView(view, params);
            }
        }

        if (pendingRequestFocus) {
            parent.restoreDefaultFocus();
        }

        if (finishInflate) {
            parent.onFinishInflate();
        }
    }
复制代码

rInflate也是调用createViewFromTag创建子View,通过递归调用rInflate创建所有子View。

2、自定义LayoutInflater实现小红书引导页

小红书引导页
来源博客:传送门

public class MyLayoutInflater extends LayoutInflater {
    private ParallaxViewImpl parallaxLayout;
    protected MyLayoutInflater(Context context, ParallaxViewImpl parallaxLayout) {
        super(context);
        this.parallaxLayout = parallaxLayout;
        setFactory2(new MyFactory(this,parallaxLayout));
    }

    @Override
    public LayoutInflater cloneInContext(Context newContext) {
        return new MyLayoutInflater(newContext, parallaxLayout);
    }
}
复制代码
public class MyFactory implements LayoutInflater.Factory2 {
    private LayoutInflater layoutInflater;
    private ParallaxViewImpl parallaxLayout;
    private final String[] sClassPrefix = {
            "android.widget.",
            "android.view.",
            "android.webkit."
    };

    public MyFactory(MyLayoutInflater myLayoutInflater, ParallaxViewImpl parallaxLayout) {
        this.layoutInflater = myLayoutInflater;
        this.parallaxLayout = parallaxLayout;
    }

    @Override
    public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
        if (name.contains(".")) {
            return createViewWithPrefix(name, null, context, attrs);
        } else {
            for (String prefix : sClassPrefix) {
                View view = createViewWithPrefix(name, prefix, context, attrs);
                if (view != null) {
                    return view;
                }
            }
        }
        return null;
    }

    @Override
    public View onCreateView(String name, Context context, AttributeSet attrs) {
        return null;
    }

    private View createViewWithPrefix(String name, String prefix, Context context, AttributeSet attrs) {
        try {
            View view = layoutInflater.createView(name, prefix, attrs);
            if (prefix == null) {
                setViewTag(view, context, attrs);
                parallaxLayout.getParallaxViews().add(view);
            }
            return view;
        } catch (Exception e) {
            return null;
        }
    }

    private void setViewTag(View view, Context context, AttributeSet attrs) {
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.animation);
        float x_in = a.getFloat(R.styleable.animation_xin, 0f);
        float x_out = a.getFloat(R.styleable.animation_xout, 0f);
        float y_in = a.getFloat(R.styleable.animation_yin, 0f);
        float y_out = a.getFloat(R.styleable.animation_yout, 0f);
        TransBean bean = new TransBean(x_in, x_out, y_in, y_out);
        view.setTag(view.getId(), bean);
        a.recycle();
    }
}
复制代码
public class MyFragment extends Fragment implements ParallaxViewImpl {
    private List<View> parallaxViews = new ArrayList<>();

    public static MyFragment newInstance(int i) {
        Bundle bundle = new Bundle();
        bundle.putInt("resId", i);
        MyFragment fragment = new MyFragment();
        fragment.setArguments(bundle);
        return fragment;
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        int resId = getArguments().getInt("resId");
        MyLayoutInflater layoutInflater = new MyLayoutInflater(getActivity(),this);
        return layoutInflater.inflate(resId, null);
    }

    @Override
    public List<View> getParallaxViews() {
        return parallaxViews;
    }
}
复制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值