手把手教你ReactNative如何調(diào)用原生自定義控件

功能需求:數(shù)字滾動動畫控件定義,并帶有單位,因ReactNative定義的動畫控件實現(xiàn)效果不佳,所以需要使用RN調(diào)用原生控件來實現(xiàn)。


具體實現(xiàn)如下:官方調(diào)用API


實現(xiàn)效果圖

1.Android原生控件定義官方鏈接。

? ? ??

原生數(shù)字滾動自定義控件實現(xiàn)

class NumberRunningFontTextView @JvmOverloads constructor(

? ? context: Context, attrs: AttributeSet? = null

) : AppCompatTextView(context, attrs) {

? ? private var currentPlayAnima: ValueAnimator? = null

? ? private var delayPlayRunnable: Runnable? = null

? ? var duration: Int = 0

? ? var currentNum: Int? = null

? ? var fontFamily: String = ""http://字體

? ? var fontSize: Int = 0 //文本顏色

? ? var fontColor: String = "#000000" //文本顏色

? ? var suffixText: String = "" //后綴文本

? ? var suffixTextFontSize: Int = 0? // 后綴文本字體大小

? ? var suffixTextFontFamily: String = "" // 后綴文本字體

? ? var suffixTextFontColor: String = "" // 后綴文本文本顏色

? ? var toFixed: Int = 0 //保留小數(shù)幾位

? ? var mLayoutRunnable :Runnable ?= null

? ? override

? ? fun onDetachedFromWindow() {

? ? ? ? super.onDetachedFromWindow()

? ? ? ? delayPlayRunnable?.let { removeCallbacks(it)}

? ? ? ? delayPlayRunnable = null

? ? ? ? mLayoutRunnable?.let { removeCallbacks(it)}

? ? ? ? mLayoutRunnable = null

? ? ? ? cancelAnim()

? ? }

? ? private fun cancelAnim() {

? ? ? ? currentPlayAnima?.run {

? ? ? ? ? ? removeAllUpdateListeners()

? ? ? ? ? ? removeAllListeners()

? ? ? ? ? ? if (isRunning) cancel()

? ? ? ? }

? ? }

? ? fun setContent(data: Int, delayPlayTime: Long = 0L) {

? ? ? ? mLayoutRunnable =Runnable {

? ? ? ? ? ? if (data == currentNum) {

? ? ? ? ? ? ? ? text = convertNum(data)

? ? ? ? ? ? ? ? return@Runnable

? ? ? ? ? ? }

? ? ? ? ? ? if (delayPlayTime > 0) {

? ? ? ? ? ? ? ? delayPlayRunnable?.let { removeCallbacks(it)}

? ? ? ? ? ? ? ? text = convertNum(currentNum ?: 0)

? ? ? ? ? ? ? ? val runnable =Runnable { useAnimByType(data)}

? ? ? ? ? ? ? ? this.delayPlayRunnable = runnable

? ? ? ? ? ? ? ? postDelayed(runnable, delayPlayTime)

? ? ? ? ? ? ? ? return@Runnable

? ? ? ? ? ? }

? ? ? ? ? ? useAnimByType(data)

? ? ? ? }

? ? ? ? mLayoutRunnable?.let {

? ? ? ? ? ? post(it)

? ? ? ? }

? ? }

? ? private fun useAnimByType(num: Int) {

? ? ? ? cancelAnim()

? ? ? ? this.playNumAnim(num)

? ? ? ? currentNum = num

? ? }

? ? private fun playNumAnim(finalNum: Int) {

? ? ? ? try {

? ? ? ? ? ? val startNum = currentNum ?: 0

? ? ? ? ? ? val intAnimator = ValueAnimator.ofInt(*intArrayOf(startNum, finalNum))

? ? ? ? ? ? this.currentPlayAnima = intAnimator

? ? ? ? ? ? intAnimator.duration = this.duration.toLong()

? ? ? ? ? ? intAnimator.addUpdateListener{ animation->

? ? ? ? ? ? ? ? if (!this@NumberRunningFontTextView.isAttachedToWindow) return@addUpdateListener

? ? ? ? ? ? ? ? val currentNum = animation.animatedValue as Int

? ? ? ? ? ? ? ? text = convertNum(currentNum)

? ? ? ? ? ? }

? ? ? ? ? ? intAnimator.addListener(onEnd ={

? ? ? ? ? ? ? ? if (!this@NumberRunningFontTextView.isAttachedToWindow) return@addListener

? ? ? ? ? ? ? ? text = convertNum(finalNum)

? ? ? ? ? ? })

? ? ? ? ? ? intAnimator.start()

? ? ? ? } catch (var5: NumberFormatException) {

? ? ? ? ? ? var5.printStackTrace()

? ? ? ? ? ? text = convertNum(finalNum)

? ? ? ? }

? ? }

? ? private fun getPattern(): String {

? ? ? ? if (toFixed > 0) {

? ? ? ? ? ? val pattern: StringBuilder = StringBuilder()

? ? ? ? ? ? pattern.append("###################0.")

? ? ? ? ? ? for (i in 0until toFixed) {

? ? ? ? ? ? ? ? pattern.append("0")

? ? ? ? ? ? }

? ? ? ? ? ? return pattern.toString()

? ? ? ? }

? ? ? ? return "###################0"

? ? }

? ? private fun convertNum(num: Int): CharSequence {

? ? ? ? val df = DecimalFormat(getPattern())

? ? ? ? val formatNum = df.format(num / 100f)

? ? ? ? val spannableString: SpannableString?

? ? ? ? if (suffixText.notNullOrEmpty()) {

? ? ? ? ? ? val txt = formatNum + suffixText

? ? ? ? ? ? spannableString = SpannableString(txt)

? ? ? ? ? ? foregroundColorSpan(spannableString, Color.parseColor(fontColor), 0, txt.length)

? ? ? ? ? ? absoluteSizeSpan(

? ? ? ? ? ? ? ? spannableString,

? ? ? ? ? ? ? ? fontSize,

? ? ? ? ? ? ? ? startIndex = 0,

? ? ? ? ? ? ? ? endIndex = txt.length

? ? ? ? ? ? )

? ? ? ? ? ? if (fontFamily.notNullOrEmpty()) {

? ? ? ? ? ? ? ? val typeface = FontManager.getInstance(context).getFont(fontFamily)

? ? ? ? ? ? ? ? fontFamilySpan(spannableString, typeface, 0, txt.length)

? ? ? ? ? ? }

? ? ? ? ? ? foregroundColorSpan(spannableString, Color.parseColor(suffixTextFontColor), formatNum?.length ?: 0, txt.length)

? ? ? ? ? ? absoluteSizeSpan(

? ? ? ? ? ? ? ? spannableString,

? ? ? ? ? ? ? ? suffixTextFontSize,

? ? ? ? ? ? ? ? startIndex = formatNum?.length ?: 0,

? ? ? ? ? ? ? ? endIndex = txt.length

? ? ? ? ? ? )

? ? ? ? ? ? if (suffixTextFontFamily.notNullOrEmpty()) {

? ? ? ? ? ? ? ? val typeface = FontManager.getInstance(context).getFont(suffixTextFontFamily)

? ? ? ? ? ? ? ? fontFamilySpan(spannableString, typeface, formatNum?.length ?: 0, txt.length)

? ? ? ? ? ? }

? ? ? ? } else {

? ? ? ? ? ? spannableString = SpannableString(formatNum)

? ? ? ? ? ? foregroundColorSpan(spannableString, Color.parseColor(fontColor), 0, formatNum.length)

? ? ? ? ? ? absoluteSizeSpan(

? ? ? ? ? ? ? ? spannableString,

? ? ? ? ? ? ? ? fontSize,

? ? ? ? ? ? ? ? startIndex = 0,

? ? ? ? ? ? ? ? endIndex = formatNum.length

? ? ? ? ? ? )

? ? ? ? ? ? if (fontFamily.notNullOrEmpty()) {

? ? ? ? ? ? ? ? val typeface = FontManager.getInstance(context).getFont(fontFamily)

? ? ? ? ? ? ? ? fontFamilySpan(spannableString, typeface, 0, formatNum.length)

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? return spannableString

? ? }

? ? private fun foregroundColorSpan(spannableString: SpannableString, color: Int, startIndex: Int = 0, endIndex: Int = 0) {

? ? ? ? val mForegroundColorSpan = ForegroundColorSpan(color)

? ? ? ? spannableString.setSpan(mForegroundColorSpan, startIndex, endIndex, Spannable.SPAN_INCLUSIVE_INCLUSIVE)

? ? }

? ? private fun fontFamilySpan(spannableString: SpannableString, typeface: Typeface, startIndex: Int = 0, endIndex: Int = 0) {

? ? ? ? if (typeface == null) {

? ? ? ? ? ? return

? ? ? ? }

? ? ? ? spannableString.setSpan(typeface, startIndex, endIndex, Spannable.SPAN_INCLUSIVE_INCLUSIVE)

? ? }

? ? private fun absoluteSizeSpan(spannableString: SpannableString, fontSize: Int, dip: Boolean = true, startIndex: Int = 0, endIndex: Int = 0) {

? ? ? ? if (fontSize <= 0) return

? ? ? ? val mAbsoluteSizeSpan = AbsoluteSizeSpan(fontSize, dip)

? ? ? ? spannableString.setSpan(mAbsoluteSizeSpan, startIndex, endIndex, Spannable.SPAN_INCLUSIVE_INCLUSIVE)

? ? }

}


供ReactNativeAPI引用具體類方法聲明實現(xiàn)

class DUNumberLabelManager : SimpleViewManager<NumberRunningFontTextView>() {

? ? override fun getName(): String = "DUNumberLabel"? ? ?//具體控件名稱定義

? ? override fun createViewInstance(reactContext: ThemedReactContext): NumberRunningFontTextView {

? ? ? ? return NumberRunningFontTextView(reactContext)

? ? }

? ? /**

?? ? *字體大小

?? ? */

? ? @ReactProp(name = "fontSize" )

? ? fun setFontSize(numberRunningFontTextView: NumberRunningFontTextView, fontSize: Int) {

? ? ? ? numberRunningFontTextView.fontSize = fontSize

? ? }

? ? /**

?? ? *字體

?? ? */

? ? @ReactProp(name = "fontFamily")

? ? fun setFontFamily(numberRunningFontTextView: NumberRunningFontTextView, fontFamily: String) {

? ? ? ? numberRunningFontTextView.fontFamily = fontFamily

? ? }

? ? /**

?? ? *文本顏色

?? ? */

? ? @ReactProp(name = "fontColor")

? ? fun setFontColor(numberRunningFontTextView: NumberRunningFontTextView, fontColor: String) {

? ? ? ? numberRunningFontTextView.fontColor = fontColor

? ? }

? ? /**

?? ? *開始數(shù)字

?? ? */

? ? @ReactProp(name = "startNum")

? ? fun setStartNum(numberRunningFontTextView: NumberRunningFontTextView, startNum: Int) {

? ? ? ? numberRunningFontTextView.currentNum = startNum

? ? }

? ? /**

?? ? *結(jié)束數(shù)字

?? ? */

? ? @ReactProp(name = "endNum")

? ? fun setEndNum(numberRunningFontTextView: NumberRunningFontTextView, endNum: Int) {

? ? ? ? numberRunningFontTextView.setContent(endNum, 500L)

? ? }

? ? /**

?? ? *動畫時長,

?? ? */

? ? @ReactProp(name = "duration")

? ? fun setDuration(numberRunningFontTextView: NumberRunningFontTextView, duration: Int) {

? ? ? ? numberRunningFontTextView.duration = duration

? ? }

? ? /**

?? ? *文本

?? ? */

? ? @ReactProp(name = "text")

? ? fun setText(numberRunningFontTextView: NumberRunningFontTextView, text: String) {

? ? ? ? numberRunningFontTextView.text = text

? ? }

? ? /**

?? ? *保留小數(shù)幾位

?? ? */

? ? @ReactProp(name = "toFixed")

? ? fun setToFixed(numberRunningFontTextView: NumberRunningFontTextView, toFixed: Int) {

? ? ? ? numberRunningFontTextView.toFixed = toFixed

? ? }

? ? /**

?? ? *行數(shù)

?? ? */

? ? @ReactProp(name = "numberOfLines")

? ? fun setNumberOfLines(numberRunningFontTextView: NumberRunningFontTextView, numberOfLines: Int) {

? ? ? ? numberRunningFontTextView.maxLines = numberOfLines

? ? }

? ? /**

?? ? *后綴文本

?? ? */

? ? @ReactProp(name = "suffixText")

? ? fun setSuffixText(numberRunningFontTextView: NumberRunningFontTextView, suffixText: String) {

? ? ? ? numberRunningFontTextView.suffixText = suffixText

? ? }

? ? /**

?? ? *后綴文本字體大小

?? ? */

? ? @ReactProp(name = "suffixTextFontSize")

? ? fun setSuffixTextFontSize(numberRunningFontTextView: NumberRunningFontTextView, suffixTextFontSize: Int) {

? ? ? ? numberRunningFontTextView.suffixTextFontSize = suffixTextFontSize

? ? }

? ? /**

?? ? *后綴文本字體

?? ? */

? ? @ReactProp(name = "suffixTextFontFamily")

? ? fun setSuffixTextFontFamily(numberRunningFontTextView: NumberRunningFontTextView, suffixTextFontFamily: String) {

? ? ? ? numberRunningFontTextView.suffixTextFontFamily = suffixTextFontFamily

? ? }

? ? /**

?? ? *后綴文本文本顏色

?? ? */

? ? @ReactProp(name = "suffixTextFontColor")

? ? fun setSuffixTextFontColor(numberRunningFontTextView: NumberRunningFontTextView, suffixTextFontColor: String) {

? ? ? ? numberRunningFontTextView.suffixTextFontColor = suffixTextFontColor

? ? }

}

? ? ? ??

把定義好的控件橋接到RNAPI 供RN調(diào)用

override fun createViewManagers(reactContext: ReactApplicationContext) =

? ? listOf(? //支持定義許多個控件

? ? ? ? DUNumberLabelManager(),? ?// 目標(biāo)控件

? ? ? ? DUNumberLabelManager1(),??

? ? ? ? DUNumberLabelManager2(),

? ? ? ? DUNumberLabelManage3r()

? ? )


2.ReactNative控件屬性定義


// DUNumberLabel.js

import PropTypes from 'prop-types';

import React from 'react';

import { NativeModules, requireNativeComponent, UIManager, findNodeHandle } from 'react-native';

const NumberLabel = requireNativeComponent('DUNumberLabel', DUNumberLabel); // 通過定義名稱,獲取原生控件

export class DUNumberLabel extends React.Component {

? render() {

? ? return

? ? ? ref={ref => this.numberLab = ref}

? ? ? fontSize={14}

? ? ? fontColor={'#000000'}

? ? ? toFixed={0}

? ? ? numberOfLines={1}

? ? ? suffixTextFontSize={12}

? ? ? suffixTextFontColor={'#000000'}

? ? ? {...this.props}

? ? />;

? }

}

DUNumberLabel.propTypes = {? // 定義控件所需屬性

? /**

?? * 字體大小

?? */

? fontSize: PropTypes.number,

? /**

?? * 字體

?? */

? fontFamily: PropTypes.string,

? /**

?? * 文本顏色

?? */

? fontColor: PropTypes.string,

? /**

?? * 開始數(shù)字

?? */

? startNum: PropTypes.number,

? /**

?? * 結(jié)束數(shù)字

?? */

? endNum: PropTypes.number,

? /**

?? * 動畫時長,秒

?? */

? duration: PropTypes.number,

? /**

?? * 文本

?? */

? text: PropTypes.string,

? /**

?? * 保留小數(shù)幾位

?? */

? toFixed: PropTypes.number,

? /**

?? * 行數(shù)

?? */

? numberOfLines: PropTypes.number,

? /**

?? * 后綴文本

?? */

? suffixText: PropTypes.string,

? /**

?? * 后綴文本字體大小

?? */

? suffixTextFontSize: PropTypes.number,

? /**

?? * 后綴文本字體

?? */

? suffixTextFontFamily: PropTypes.string,

? /**

?? * 后綴文本文本顏色

?? */

? suffixTextFontColor: PropTypes.string,

};


3.ReactNative引用部分?

????<DUNumberLabel

?? ? ? ? ? style={{ ...styles.total, width: '100%' }}

?? ? ? ? ? fontSize={20}

?? ? ? ? ? fontFamily={DUFont.family.helveticaNeueCondensedBold}

?? ? ? ? ? fontColor={'#000fff'}

?? ? ? ? ? startNum={10000}

?? ? ? ? ? endNum={9999000}

?? ? ? ? ? duration={5000}

?? ? ? ? ? toFixed={2}

?? ? ? ? ? suffixText={"億萬"}

?? ? ? ? ? suffixTextFontSize={12}

?? ? ? ? ? suffixTextFontFamily={'HelveticaNeue-CondensedBold'}

?? ? ? ? ? suffixTextFontColor={'#14151A'}

?? ? ? />


注意事項:

? ? 1.注意ReatctNative調(diào)用通用控件封裝版本更新后, 本地也需要重新更新保持安裝版本內(nèi)代碼包含定義控件

校驗兩個文件版本是否一致

????2.調(diào)用APK需包含上述原生控件封裝代碼否則會找不到原生控件


? ? 3.單位跳動問題:在原生自定義控件?NumberRunningFontTextView 新增? ? ?gravity = Gravity.RIGHT

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容