How to create a custom native ImageView/View in Android or iOS for ReactNative?

By | August 10, 2018

Many times we need custom components from native.

Here is a simple example on how to create a custom imageview in Android for react native.

First we will start with the Android Version

Android

  • Create a class that extends SimpleViewManager.
  • Write a setSrc method which accepts the source url from React Native.
  • Implement ‘createViewInstance’ method in which you can create the ImageView instance.
  • Listen for the setter to set the url and then start downloading the image.
  • Require the Native Component and set the import the ImageView just created from Native to React Native.
  • Pass the properties

and you are done.

Lets Start…

Java Class

Here is the complete class that creates the imageview and downloads the image.


import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.support.annotation.Nullable;
import android.util.Log;

import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.views.image.ReactImageView;

import java.net.URL;

public class ReactImageManager extends SimpleViewManager<ReactImageView> {

    public static final String REACT_CLASS = "RCTImageView1";
    private final @Nullable
    Object mCallerContext = null;
    private ImgStartListener imgStartListener;

    /* Interface Listener to start loading the image if the source is set */
    private interface ImgStartListener {
        void startLoading(String imgUrl);
    }

    @Override
    public String getName() {
        return REACT_CLASS;
    }

    /* Method which sets the source from React Native */
    @ReactProp(name = "src")
    public void setSrc(ReactImageView view, String uri) {
        imgStartListener.startLoading(uri);
    }

    @Override
    protected ReactImageView createViewInstance(ThemedReactContext reactContext) {

        final ReactImageView reactImageView = new ReactImageView(reactContext, Fresco.newDraweeControllerBuilder(), null, mCallerContext);

        final Handler handler = new Handler();
        imgStartListener = new ImgStartListener() {
            @Override
            public void startLoading(final String imgUrl) {
                startDownloading(imgUrl, handler, reactImageView);

            }
        };

        return reactImageView;
    }

    private void startDownloading(final String imgUrl, final Handler handler, final ReactImageView reactImageView) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    URL url = new URL(imgUrl);
                    final Bitmap bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
                    setImage(bmp, handler, reactImageView);
                } catch (Exception e) {
                    Log.e("ReactImageManager", "Error : " + e.getMessage());
                }
            }
        }).start();
    }

    private void setImage(final Bitmap bmp, Handler handler, final ReactImageView reactImageView) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                reactImageView.setImageBitmap(bmp);
            }
        });
    }
}

You can improve this view the way you want. This is only a simple implementation of an image.

Add to ViewManagers

Next step is to add this to a viewmanagers list.
Create a class named say “AnExampleReactPackage” and implement ReactPackage.
Add the above class to the ‘createViewManagers’ method.


import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import com.helloworld.ToastModule;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class AnExampleReactPackage implements ReactPackage {

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Arrays.<ViewManager>asList(
                new ReactImageManager()
        );
    }

}

Add to MainApplication List

This is final step where you add the package so that React Native can detect your view.

public class MainApplication extends Application implements ReactApplication {

    private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
        @Override
        public boolean getUseDeveloperSupport() {
            return BuildConfig.DEBUG;
        }

        @Override
        protected List<ReactPackage> getPackages() {
            return Arrays.<ReactPackage>asList(
                    new MainReactPackage(),
                    new VectorIconsPackage(),
                    // add here
                    new AnExampleReactPackage()
            );
        }

        @Override
        protected String getJSMainModuleName() {
            return "index";
        }
    };

    @Override
    public ReactNativeHost getReactNativeHost() {
        return mReactNativeHost;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        SoLoader.init(this, /* native exopackage */ false);
    }
}

In React Native

Create a file named ‘ImageView.js’ and copy the below code into it.

import PropTypes from 'prop-types';
import {requireNativeComponent, ViewPropTypes} from 'react-native';

var iface = {
  name: 'ImageView',
  propTypes: {
    src: PropTypes.string,
    borderRadius: PropTypes.number,
    resizeMode: PropTypes.oneOf(['cover', 'contain', 'stretch']),
    ...ViewPropTypes, // include the default view properties
  },
};

module.exports = requireNativeComponent('RCTImageView1', iface);

Usage

  <ImageView
        src={ 'your_img_url' }
        style={{width: 100, height: 100}}
  />

Now we will look at ios. Here instead of creating an ImageView, I am creating just a view in iOS.

iOS

Create new Files inside your application say”NativeView”.

Create Cocoa Files NativeView.m and .h

Now open NativeView.h and copy this code

    #import <Foundation/Foundation.h>

    #import <React/RCTViewManager.h>

    @interface NativeView : RCTViewManager

    @end

RCTViewManager is the base class for view in React Native for iOS.

Now in NativeView.m

    #import "NativeView.h"

    @implementation NativeView

    RCT_EXPORT_MODULE()
    - (UIView *)view
    {
      UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
      view.backgroundColor = [UIColor blueColor];
      return view;
    }

    @end

Use it same like android

    import { requireNativeComponent } from 'react-native';

    // requireNativeComponent automatically resolves 'RNTMap' to 'RNTMapManager'

    module.exports = requireNativeComponent('NativeView', null);

Leave a Reply

Your email address will not be published. Required fields are marked *