React Native Android之原生UI組件動態(tài)addView不顯示問題解決

React Native Android之原生UI組件動態(tài)addView不顯示問題解決

版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載。

轉(zhuǎn)載請表明出處:http://www.lxweimin.com/p/a6c5042c5ce8

[TOC]

在如今的App中,已經(jīng)有成千上萬的原生UI部件了——其中的一些是平臺的一部分,另一些可能來自于一些第三方庫,而且可能你自己還收藏了很多。React Native已經(jīng)封裝了大部分最常見的組件,譬如ScrollViewTextInput,但不可能封裝全部組件。而且,說不定你曾經(jīng)為自己以前的App還封裝過一些組件,React Native肯定沒法包含它們。幸運的是,在React Naitve應(yīng)用程序中封裝和植入已有的組件非常簡單。但在實施的過程中往往會發(fā)生一些小狀況,如今天分享的這個問題,當(dāng)原生UI組件動態(tài)addView時在界面中不顯示。
(下面React Native 簡稱為RN)

還原場景

在下面代碼中,我們定義了一個原生的控件,這個組件同樣也可用于RN。

public class RCTVideoLayout extends RelativeLayout {

    public RCTVideoLayout(Context context) {
        this(context, null);
    }

    public RCTVideoLayout(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RCTVideoLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context);
    }

    /**
     * 初始化View
     *
     * @param context
     */
    private void initView(Context context) {
        View rootView = View.inflate(context, R.layout.video_layout, null);
        addView(rootView);
    }

    /**
     * 動態(tài)添加View
     * @param str
     */
    public void autoAddView(String str){
        Button button = new Button(getContext());
        button.setText(str);
        addView(button);
    }

在這段上面的autoAddView函數(shù)中就是一個動態(tài)添加View的操作,如果這段代碼在原生中執(zhí)行是沒問題的,但在RN中動態(tài)調(diào)用,會導(dǎo)致無論addView多少次都沒問題,但在RN中每次調(diào)用均在UI中看不出有什么明顯變化,通過斷點也是沒發(fā)現(xiàn)問題所在,那么究竟是什么原因?qū)е碌哪兀旅嫖医o大家分析一下。

利用工具分析問題所在

發(fā)生如此詭異的情況,該怎么分析呢?Android Studio中有個工具Layout inspector,這個工具可以快速對手機上面的界面做分析。

  • Android Studio打開任意工程后,按照如下圖所示:
    WechatIMG11
  • 等待幾秒后,會自動打開分析界面:
屏幕快照 2017-09-06 上午11.06.47.png
  • 這個界面是一個Demo工程,里面同樣也是用RN調(diào)用原生封裝的組件,但同樣的情況是調(diào)用了原生addView后,并沒有在UI上看到

  • 現(xiàn)在把所有的層級打開后,發(fā)現(xiàn)原生的確已經(jīng)addView進去了,只不過他的height和 width 都是0,所以這樣就能解釋為什么我們動態(tài)添加View后看不到UI變化。

    WechatIMG8

解決方案

  • 從上圖中可以分析得到,無論我們addView多少次,所產(chǎn)生的View都是0高0寬,這個明顯就是沒有讓ViewGroup去測量子控件。現(xiàn)在原因已經(jīng)明了,那么如何解決這種問題呢?那當(dāng)然是讓ViewGroup每次都自己測量子控件的高寬咯,我們回到剛才的自定義ViewGroup中的代碼中,添加如下代碼:

    //以下代碼修復(fù)通過動態(tài) addView 后看不到的問題
    
    @Override
    public void requestLayout() {
        super.requestLayout();
        post(measureAndLayout);
    }
    
    private final Runnable measureAndLayout = new Runnable() {
        @Override
        public void run() {
            measure(
                    MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY),
                    MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.EXACTLY));
            layout(getLeft(), getTop(), getRight(), getBottom());
        }
    };
    
  • 以上代碼中所作的事情就是每次addView后,在ViewGroup源碼中可看到addView后,實際調(diào)用requestLayout()函數(shù),如下圖所示:

屏幕快照 2017-09-06 上午11.21.06.png
  • 添加代碼后,我們再次運行程序,再次通過Layout inspector工具來看看效果:

    WechatIMG9
  • 可以發(fā)現(xiàn)這回終于有顯示了,再看到hight和width都有對應(yīng)的值了。

總結(jié)

以上是我在封裝原生控件給RN調(diào)用時遇到的一個問題,歡迎大家支持。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容