RN Native UI Componentを作成

6765 ワード

RNにはすでに開発者用のUIコンポーネントが多く提供されており、コミュニティには第三者のオープンソースUIコンポーネントも多く開発者用に使用されています.しかし、アプリケーション開発の過程で、UIコンポーネントをカスタマイズしてニーズを満たす必要は避けられません.
本稿では,主にスライド(ダブルクリック)で画像を拡大・縮小してコンポーネントを得ることによって,UI Componentを作成する方法を共有する.
テキストの前
最初は公式サイトのこの文章を見ただけだったが、システムのコンポーネント(Image,ScrollViewなど)の実現を見に行かなかった.ジェスチャーを監視して縮小画像を拡大・縮小する方法を考えたとき、私の最初の考えは「RNでユーザーの手勢を監視・取得する方法」だった..これらを見終わったら、ソースコードのScrollViewがジェスチャーをどのように処理しているかを見てみましょう.実際には、RNでNative UI Componentとして呼び出されたNativeのScrolViewのみである.ジェスチャーの効果についてはNative ScrollView自身の処理です.後で考えてみると、RNは最終的にレンダリングされたNativeコンポーネントであることに気づきました.Nativeコンポーネント自体の機能は使用できますが、RN Native UI Componentの形式でNativeコンポーネントに初期のプロパティを設定するだけです.
実現構想.
「スライド(ダブルクリック)をして拡大/縮小してコンポーネントを得る方法」を考えてみましょう.Nativeにこの機能のあるコンポーネントを書いて、RNでこのコンポーネントを使えばいいのです.RNのピクチャロードにはFrescoフレームワークが使用されており,Frescoベースのピクチャ拡大縮小コントロールPhotodaweeViewが既に存在すると考えられる.だから、PhotodaweeViewを直接使うことができます.考えがはっきりしてから、やり始めた.
Nativeでのコントロールの定義
Nativeでは、PhotodaweeViewとして、JSでPropsでコントロールを設定するためのデータソース(ピクチャアドレス)と、ピクチャを実際にロードするための2つの方法が暴露されています.
public class ZoomableImageView extends PhotoDraweeView {
    private Uri mUri = null;
    public ZoomableImageView(Context context) {
        super(context);
    }
    public void setSource(@Nullable String source, @NonNull ResourceDrawableIdHelper resourceDrawableIdHelper) {
        if (source != null) {
            try {
                mUri = Uri.parse(source);
                if (mUri.getScheme() == null) {
                    mUri = null;
                }
            } catch (Exception ignore) {
            }
        }
    }
    //from PhotoDraweeView demo
    public void updateIfNeeded() {
        if (mUri == null) {
            return; //      
        }
        PipelineDraweeControllerBuilder controller = Fresco.newDraweeControllerBuilder();
        controller.setUri(mUri);
        controller.setOldController(getController());
        // You need setControllerListener
        controller.setControllerListener(new BaseControllerListener() {
            @Override
            public void onFinalImageSet(String id, ImageInfo imageInfo, Animatable animatable) {
                super.onFinalImageSet(id, imageInfo, animatable);
                if (imageInfo == null) {
                    return;
                }
                update(imageInfo.getWidth(), imageInfo.getHeight());
            }
        });
        setController(controller.build());
        setOnPhotoTapListener(new OnPhotoTapListener() {
            @Override
            public void onPhotoTap(View view, float x, float y) {
                Toast.makeText(view.getContext(), "onPhotoTap :  x =  " + x + ";" + " y = " + y,
                        Toast.LENGTH_SHORT).show();
            }
        });
        setOnViewTapListener(new OnViewTapListener() {
            @Override
            public void onViewTap(View view, float x, float y) {
                Toast.makeText(view.getContext(), "onViewTap", Toast.LENGTH_SHORT).show();
            }
        });
        setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                Toast.makeText(v.getContext(), "onLongClick", Toast.LENGTH_SHORT).show();
                return true;
            }
        });
    }
}


View Manager
View Managerについて詳しくない場合は、公式サイトの紹介を参照してください.View Managerは、主にコンポーネントのNameと、どのようなプロパティが露出するかを決定します.
  • createViewInstanceメソッド特定のコンポーネントを作成する
  • getNameメソッドでComponentのNameが決定され、JSで呼び出されたときにNameで呼び出された
  • @ReactPropはNativeが暴露した属性とJSにおけるコントロールpropsの対応関係
  • を決定する.
  • 特筆すべきはonAfterUpdateTransactionメソッドであり、このコールバックは@ReactProp注釈のあるすべてのメソッドがプロパティを更新した後に呼び出されます.私たちはそれを通じて具体的な画像をロードします.
  • public class ZoomableImageViewManager extends SimpleViewManager {
        private static final String REACT_CLASS = "ZoomableImageViewAndroid";
    
        private ResourceDrawableIdHelper mResourceDrawableIdHelper;
    
        ZoomableImageViewManager(ReactApplicationContext context) {
            mResourceDrawableIdHelper = new ResourceDrawableIdHelper();
        }
    
        @Override
        public String getName() {
            return REACT_CLASS;
        }
    
        @Override
        protected ZoomableImageView createViewInstance(ThemedReactContext reactContext) {
            return new ZoomableImageView(reactContext);
        }
    
        @ReactProp(name = "src")
        public void setSource(ZoomableImageView view, @Nullable String source) {
            view.setSource(source, mResourceDrawableIdHelper);
        }
    
        @Override
        protected void onAfterUpdateTransaction(ZoomableImageView view) {
            super.onAfterUpdateTransaction(view);
            view.updateIfNeeded();
        }
    }
    

    Register the ViewManager
    コンポーネントをReact Packageに登録します.
    public class ZoomableImageViewPackage implements ReactPackage {
        @Override
        public List> createJSModules() {
            return Collections.emptyList();
        }
    
        @Override
        public List createViewManagers(ReactApplicationContext reactContext) {
            List viewManagers = new ArrayList<>();
            viewManagers.add(new ZoomableImageViewManager(reactContext));
            return viewManagers;
        }
    
        @Override
        public List createNativeModules(ReactApplicationContext reactContext) {
            return Collections.emptyList();
        }
    }
    

    Native初期化時に対応するReact Packageをロード
    RN JSでこのNativeコンポーネントを呼び出すには、React Packageを初期化する必要があります.
     @Override
        protected List getPackages() {
            return Arrays.asList(
                    new MainReactPackage(),
                    new ZoomableImageViewPackage(),
            );
        }
    

    RN JSでNativeコンポーネントを使用
    export default class ZoomableImageView extends Component {
      static propTypes = {
          src: PropTypes.string,
          ...View.propTypes
      };
      render() {
        if (this.props.src) {
          console.warn('src is null');
        }
          return 
        }
        return null
      }
    }
    const ZoomableImageViewAndroid = requireNativeComponent('ZoomableImageViewAndroid', ZoomableImageView);
    

    最後に、ダブルクリックをサポートし、ダブル指スライドで拡大縮小を実現する画像閲覧コントロールが実現されます.PhotoDraweeViewを使用して、特定のジェスチャーリスニングと画像スケール機能を実現します.PhotoDraweeViewにはいくつかの有用な構成があり、JSに露出して構成する場合は@ReactProp注釈で露出します.
    機能を実現するとともに,実際にはCustomUI Componentに対する理解を深める.Android自体のコントロールライブラリは豊富で、Custom UI Componentの形式でJSでNativeコンポーネントを使用することができます.
    では、RNのListViewはなぜNativeによって実現されないのでしょうか.