React-Native 安卓自定义View(一)

React-Native 安卓自定义View(一)

在移动端开发中,使用React-Native的越来越多,其使用js作为开发语言,并且提供大量的组件,大大提升了移动端开发的效率。但是最近在使用的过程中发现,RN提供的一些组件不能满足特定的业务需求,需要通过自定义view来实现。
查了很多网上的文章,大部分的文章只是简单的介绍了如何自定义view,但是并没有介绍怎么通过RN控制view的样式(css),以及view的一些相关事件的使用(比如TextInput的onBlur()等)
那么还是自己来吧,我们首先来看一下,RN是怎么使用css来控制view的样式的。


自定义view并控制其样式:
我们首先看一下RN的TextInput,它的位置在在node_modules/react-native/Libraries/Components/TextInput/TextInput.js

React-Native 安卓自定义View(一)_第1张图片

在render方法中判断当前系统,如果是安卓执行_renderAndroid()方法。在这个方法的返回中,发现实际是AndroidTextInput。
React-Native 安卓自定义View(一)_第2张图片

在这里我们看到AndroidTextInput中有onFocus、onBlur、onChange等方法,这个在后面会介绍这些方法是如何被调用的。
同样,我们也看到在AndroidTextInput中有“{…props}”,这句话是什么意思就不用赘述了吧。

React-Native 安卓自定义View(一)_第3张图片

看到这里发现在引用Java了。组件的名字叫“AndroidTextInput”。通过搜索在rn的源码中找到ReactTextInputManager.java,如下:
React-Native 安卓自定义View(一)_第4张图片

根据getName()方法可知,在js层使用的TextInput实际上就是这个manger提供的。那就来仔细查看这个类吧。在使用TextInput时,我们经常用到的样式大致有width、height、backgroundColor、fontSize等等,下面就以fontSize为例查找。在ReactTextInputManager.java中发现有这么一个方法:
React-Native 安卓自定义View(一)_第5张图片

在这里看到了这个方法使用了注解@ReactProp(name = ViewProps.FONT_SIZE,defaultFloat = ViewDefaults.FONT_SIZE_SP),由此推断,rn在创建这个input时会调用带有ReactProp注解的方法,并将对应的值传入。(通过查看源码证明就是如此)。我们还发现,在设置fontSize时我们并没有指定单位,比如“fontSize:20”在这里会不难发现其实单位是sp而非px。

好了,对于源码探究先到此结束,下面开始打造自己的TextInput。首先自定义一个view,extends EditText。

import com.facebook.react.bridge.ReactContext;


/**
 * @Title:
 * @Desc:
 * @CreateTime: 2017-08-04 11:07
 * @Creator: Liy
 * @Version: 1.0
 */

@SuppressLint("AppCompatCustomView")
public class RNEditText extends EditText {


    public RNEditText(ReactContext reactContext) {
        super(reactContext);
    }
}

代码很简单,只是定义了一个EditText,没有做其他事情。然后创建一个manager extends BaseViewManager,代码如下:

/**
 * @Title:
 * @Desc:
 * @CreateTime: 2017-08-04 13:44
 * @Creator: Liy
 * @Version: 1.0
 */

public class RNEditTextManager extends BaseViewManager {


    public static final String MANAGER_NAME = "RNEditText";


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

    @Override
    public LayoutShadowNode createShadowNodeInstance() {
        return new ReactTextInputShadowNode();
    }

    @Override
    public Class getShadowNodeClass() {
        return ReactTextInputShadowNode.class;
    }

    @Override
    protected RNEditText createViewInstance(ThemedReactContext reactContext) {
        final RNEditText rnEditText = new RNEditText(reactContext);
        return rnEditText;
    }

    @Override
    public void updateExtraData(RNEditText root, Object extraData) {

    }


}

这个manager也很简单,下面就把fontSize加上去。如下:

@ReactProp(name = ViewProps.FONT_SIZE, defaultFloat = ViewDefaults.FONT_SIZE_SP)
    public void setFontSize(RNEditText view, float fontSize) {
        view.setTextSize(
                TypedValue.COMPLEX_UNIT_PX,
                (int)   Math.ceil(PixelUtil.toPixelFromSP(fontSize)));
    }

其实就是将rn里的源码复制到这里。然后在js层验证发现是有效果的。做到这里,我们如果想定义一个rn源码里不存在的样式是否可行呢,答案是肯定的。通过查看源码发现,rn在处理样式和属性的方式是一样的,事实上rn会把所有的样式都转换成为属性,然后去对应的viewManager类中查找带有ReactProp注解的方法。

在后续的章节中会介绍如何处理自定义view的一些事件。

这里就不把结果贴出来了,有兴趣的同学可以找我要源码。
我的QQ:243869018

你可能感兴趣的:(react-native)