compose 部分
先附一个官方教程链接
核心是一个AndroidView,AndroidView也是一个@Composable,他的factory方法可以接收一个非compose 的view。官方示例的核心代码是这一段:
/**
* ****************compose ui 中使用未实现compose版本ui的关键
AndroidView采用以编程方式创建的View。如果您想嵌入XML文件,
则可以使用androidx.compose.ui:ui-viewbinding库中的视图绑定和AndroidViewBinding API来使用
*/
@Composable
private fun PlantDescription(description: String) {
val htmlDescription = remember(description) {
HtmlCompat.fromHtml(description,HtmlCompat.FROM_HTML_MODE_COMPACT)
}
AndroidView(factory = { context -> TextView(context).apply {
movementMethod = LinkMovementMethod.getInstance()
}
},
update = {
it.text = htmlDescription
}
)
//在显示时在屏幕上显示TextView并使用HTML描述进行更新
// 更新htmlDescription将使AndroidView重构并更新文本
}
TextView 有对富文本的实现,现有(1.0.0-bate06)的compose 并没有现有的实现。
示例部分(MPAndroidChart):
先附一个MPAndroidChart的GitHub
所有的写法应以官网文档为准。
首先,利用AndroidView,建立一个chart对象,我们以普通的LineChart为示例。compose UI不需要xml部分,可以把AndroidView的factory 简单理解为xml的放置操作。当然之前在代码部分初始化的内容也可以放置在里面。
简单代码示例:
AndroidView(
factory = { context ->
LineChart(context).apply {
lineChart = this
this.setViewPortOffsets(0F, 0F, 0F, 0F)
this.setBackgroundColor(0XFFFFFF)
//说明文字
this.description.isEnabled = false
// 启用触摸手势
this.setTouchEnabled(true)
// 启用缩放和拖动
this.isDragEnabled = true
this.setScaleEnabled(true)
// 如果禁用,则可以分别在x轴和y轴上进行缩放
this.setPinchZoom(false)
this.setDrawGridBackground(false)
this.maxHighlightDistance = 300f
val x = this.xAxis
x.isEnabled = false
val y = this.axisLeft
//y.typeface = tfLight
y.setLabelCount(6, false)
y.textColor = Color.WHITE
y.setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART)
y.setDrawGridLines(false)
y.axisLineColor = Color.WHITE
this.axisRight.isEnabled = false
this.legend.isEnabled = false
//this.animateXY(1500, 1500)
}
},
update = {
if (setData(it, value)) {
it.data.dataSets[0].setDrawValues(true)
}
Timber.i("update chart")
//it.legend.isEnabled = false
it.animateXY(1500, 1500)
},
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
)
factory 结束之后是会执行update ,关系就像oncreate跟onstart.
上面代码有2个问题:
- 是setData(it, value) 是一个fun ,
- 是MPAndroidChart的刷新代码是animateXY()方法,update的绑定甚至不能触发。
刷新视图可以把对象生域,然后在外面手动调用setData() 和 animateXY () 方法,这里贴一个测试刷新的代码:
//todo test
GlobalScope.launch {
delay(6000)
Timber.i("change value")
value = value2
if (setData(lineChart!!, value)) {
lineChart!!.data.dataSets[0].setDrawValues(true)
}
withContext(Dispatchers.Main){
lineChart?.animateXY(1500, 1500)
}
}
至于setData()方法,fun 里面是可以再fun 的,只不过跟c语言一样,要写在使用的前面。具体setData方法,可以参考MPAndroidChart官方文档。
5月28日修正:
MPAndroidChart 引入livedata后可以触发update,所以修正部分代码:
val value by ViewModel.data.observeAsState()
......
update = {
//给默认值可以去掉空判断
value?.let { value->
if (setData(it, value)) {
it.data.dataSets[0].setDrawValues(true)
}
it.animateXY(1500, 1500)
}
}
GlobalScope.launch 不是compose ui 中调用协程的正确方式推荐使用LaunchedEffect()