Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> React-Native系列Android自定義原生UI組件

React-Native系列Android自定義原生UI組件

編輯:關於Android編程

由於官方的Android原生UI組件解釋的並不是很完整,根據個人的不斷摸索,終於成功完成原生組件的制作,所以寫下這篇文章作為記錄,也給讓小白們少走些彎路。

我這裡通過講解制作一個繪圓組件的流程,來學習制作android原生UI組件。這個繪圓組件並沒有實際的使用價值,只是為了更容易的了解android原生UI組件的制作過程。好了廢話不多說,現在開始吧。

react-native版本:0.33.0

首先初始化react-native項目,最好能弄個VPN

react-native init AndroidNativeModule

初次build android項目,先打開虛擬機或連接手機。

react-native run-android

項目的創建就講到這,詳細的項目創建和排錯請自行百度。現在我們用Android Stuido進入android項目。

創建基本的UI組件框架,這裡組件名稱嚴格更具功能進行命名,為了看的更清楚進行了一些打包
項目目錄

CircleManager.java CIrcle原生組件管理器,實現JS和JAVA信息傳遞 CircleView.java Circle原生組件 MainPackage.java 自定義組件注冊包

接下來給創建好的java添加基本結構,然後在後面更具需要添加細節功能

CircleView.java 基礎結構
package com.androidnativemodule.module.circle;

import android.content.Context;
import android.view.View;

/**
 * 圓形組件組件基礎類
 */
public class CircleView extends View {

    public CircleView(Context context) {
        super(context);
    }
}

UI組件繼承於View類,這裡沒有加什麼功能,就創建一個基本的類

CircleManager.java
package com.androidnativemodule.module.circle;

import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;

/**
 * 圓形組件基礎類管理器
 */
public class CircleManager extends SimpleViewManager {

    /**
     * 設置js引用名
     * @return String
     */
    @Override
    public String getName() {
        return "MCircle";
    }

    /**
     * 創建UI組件實例
     * @param reactContext
     * @return CircleView
     */
    @Override
    protected CircleView createViewInstance(ThemedReactContext reactContext) {
        return new CircleView(reactContext);
    }
}

所有的組件管理器需要繼承SimpleViewManager類,後面加上自己定義的組件基礎類,下面2個方法是SimpleViewManager類的必須實現的方法,記住getName()返回的名字要和JS裡的應用名進行統一。

MainPackge.java
package com.androidnativemodule;

import com.androidnativemodule.module.circle.CircleManager;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * 自定義組件模塊注冊類
 */
public class MainPackage implements ReactPackage {

    /**
     * 創建原生模塊
     * @param reactContext
     * @return
     */
    @Override
    public List createNativeModules(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }

    @Override
    public List> createJSModules() {
        return Collections.emptyList();
    }

    /**
     * 創建原生UI組件控制器
     * @param reactContext
     * @return
     */
    @Override
    public List createViewManagers(ReactApplicationContext reactContext) {
        return Arrays.asList(
            new CircleManager()
        );
    }
}

這個是注冊類,實現ReactPackage接口,可以想自己設計的組件統一寫在這個類中,然後一起在Application中注冊,注意:返回空值需要返回Collections.emptyList()。它還可以注冊原生模塊,這個官方有詳細的講解,地址如下:http://facebook.github.io/react-native/docs/native-modules-android.html

注冊類寫好後,還需要將這個類加載進Application中,我們在通過MainApplication中將其加入進去。

MainApplication.java
package com.androidnativemodule;

import android.app.Application;
import android.util.Log;

import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;

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

public class MainApplication extends Application implements ReactApplication {

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

    @Override
    protected List getPackages() {
      return Arrays.asList(
          new MainReactPackage(),
          new MainPackage() // 在這裡加載我們自己的注冊類
      );
    }
  };

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

到這裡我們的自定義UI組件框架基本完成,我們可以run一下看看,如果沒有效果,可以嘗試重新react-native run-android 下。

在Android Monitor中可以看到已經加載了我們的CircleModule,只有有沒我們JS並沒有實例話他,所以Could not find generated setter for class com.androidnativemodule.module.circle.CircleManager。
Android Monitor截圖

接下來我們給我們的原生UI組件加上功能。<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxjb2RlPjxjb2RlPjxjb2RlPkNpcmNsZVZpZXcuamF2YSA8L2NvZGU+PC9jb2RlPjwvY29kZT4NCjxwcmUgY2xhc3M9"brush:java;"> package com.androidnativemodule.module.circle; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.util.Log; import android.view.View; /** * 圓形組件組件基礎類 */ public class CircleView extends View { protected String TAG = "CircleView"; private Paint mPaint; // 畫筆 public CircleView(Context context) { super(context); mPaint = new Paint(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawCircle(100, 100, 100, mPaint); // 畫一個半徑為100px的圓 Log.d(TAG, "繪圖"); } }

這裡我先在CircleView內寫死代碼,看看這個原生UI到底能不能在JS中使用

現在我們來到react-native項目,我們先定制一個Circle組件的JS接口,方便其他組件調用。

創建Circle.js
import { PropTypes } from 'react';
import { requireNativeComponent, View } from 'react-native';

const MCircle = requireNativeComponent('MCircle', {
  propTypes: {
    ...View.propTypes // 包含默認的View的屬性
  },
});

export default MCircle;

使用requireNativeComponent根據先前在管理器中定義好的組件名引用原生組件,由於我們還沒創建接口,所以這個組件暫時只有父類View的接口。

現在我們在index.android.js中實例化組件看看效果

index.android.js
'use strict';

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View
} from 'react-native';
import Circle from './Circle';

class AndroidNativeModule extends Component {
  render() {
    return (
      
        
      
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  }
});

AppRegistry.registerComponent('AndroidNativeModule', () => AndroidNativeModule);

效果圖:
模擬器截圖

可以看到成功使用Android canvas 畫了一個圓

現在我們給他加一些接口,從而實現JS和JAVA的通訊,直接在JS中更改組件樣式。

CircleView.java
package com.androidnativemodule.module.circle;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.Log;
import android.view.View;

import com.facebook.react.uimanager.PixelUtil;

/**
 * 圓形組件組件基礎類
 */
public class CircleView extends View {

    protected String TAG = "CircleView";
    private Paint mPaint; // 畫筆
    private float mRadius;  // 圓的半徑

    public CircleView(Context context) {
        super(context);
        mPaint = new Paint();
    }

    /**
     * 設置圓的背景色
     * @param color
     */
    public void setColor(Integer color) {
        mPaint.setColor(color); // 設置畫筆顏色
        invalidate();   // 更新畫板
    }

    /**
     * 設置圓的半徑
     * @param radius
     */
    public void setRadius(Integer radius) {
        /**
         * 由於JS傳過的數字是dip單位,需要轉換為實際像素
         * 使用com.facebook.react.uimanager包中的PixelUtil,進行轉換
         */
        mRadius = PixelUtil.toPixelFromDIP(radius);
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawCircle(100, 100, 100, mPaint); // 畫一個半徑為100px的圓
        Log.d(TAG, "繪圖");
    }
}

這裡添加了2個接口,實現對圓的大小和顏色更改,還使用了PixelUtil實現像素的轉換

CircleManager.java
package com.androidnativemodule.module.circle;

import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.annotations.ReactProp;

/**
 * 圓形組件基礎類管理器
 */
public class CircleManager extends SimpleViewManager {

    /**
     * 設置js引用名
     * @return String
     */
    @Override
    public String getName() {
        return "MCircle";
    }

    /**
     * 創建UI組件實例
     * @param reactContext
     * @return CircleView
     */
    @Override
    protected CircleView createViewInstance(ThemedReactContext reactContext) {
        return new CircleView(reactContext);
    }

    /**
     * 傳輸背景色參數
     * @param view
     * @param color
     */
    @ReactProp(name = "color")
    public void setColor(CircleView view, Integer color) {
        view.setColor(color);
    }

    /**
     * 傳輸半徑參數
     * @param view
     * @param radius
     */
    @ReactProp(name = "radius")
    public void setRadius(CircleView view, Integer radius) {
        view.setRadius(radius);
    }
}

管理器中引用接口,將參數傳輸過去

現在我們的CircleModule已經完成了,然後我們修改下Circle組件JS接口,實現接口使用。

Circle.js
'use strict';

import React, { Component, PropTypes } from 'react';
import {
  View,
  requireNativeComponent,
  processColor  // 字符Color轉換為數字
} from 'react-native';

const MCircle = requireNativeComponent('MCircle', {
  propTypes: {
    color: PropTypes.number,
    radius: PropTypes.number,
    ...View.propTypes // 包含默認的View的屬性
  },
});

class Circle extends Component {

  static propTypes = {
    radius: PropTypes.number,
    color: PropTypes.string, // 這裡傳過來的是string
    ...View.propTypes // 包含默認的View的屬性
  }

  render() {
    const { style, radius, color } = this.props;

    return (
      
    );
  }

}

module.exports = Circle;

由於color使用的是String,我們可以用react-native的processColor將其轉換為數字,從而可以讓java識別出顏色,為了方便使用,所以我這邊重寫創建了Component,作為中間組件,對color進行轉換。

然後我的就可以通過Circle.js使用CircleModule了,例如:

效果圖:
模擬器截圖

到此Android自定義原生UI組件CircleModule的設計就結束了,如果有錯誤的地方,大家可以指出來反饋給我,也希望大家可以將自己的react-native開發心得分享出來,大家一起來學習。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved