如果界面的某些部分无效,Compose 会尽力只重组需要更新的部分。这意味着,它可以跳过某些内容以重新运行单个按钮的可组合项,而不执行界面树中在其上面或下面的任何可组合项。
import com.m8test.script.GlobalVariables.*
import com.m8test.script.core.api.ui.compose.modifier.Modifier
import com.m8test.script.core.api.ui.compose.slot.Slot
import com.m8test.script.core.api.ui.compose.state.MutableState
import com.m8test.script.core.api.ui.compose.state.MutableStateList
/**
* 显示用户可以点击的带有标题的名称列表
*/
private fun NamePicker(slot: Slot<out Modifier>, header: MutableState<String>, names: MutableStateList<String>, onNameClick: (String) -> Unit) {
slot.Column {
setContent {
Text {
// 当 [header] 发生改变时,它将被重新组合,但当 [names] 发生改变时,它将不会被重新组合
trackSingleState(header)
setText(header.getValue())
}
HorizontalDivider {}
// LazyColumn 是 RecyclerView 的 Compose 版本。
// 传递给 items() 的 lambda 类似于 RecyclerView.ViewHolder
LazyColumn {
setContent {
itemsIndexed(names, null, null) { index, name ->
// 当某个项目的 [name] 更新时,该项目的适配器将进行重组。当 [header] 更改时,此适配器不会进行重组
NamePickerItem(this, name, onNameClick)
}
}
}
}
}
}
/**
* 显示用户可以点击的单个名称。
*/
private fun NamePickerItem(slot: Slot<out Modifier>, name: String, onClick: (String) -> Unit) {
slot.Text {
setText(name)
setModifier {
clickable(true, null, null) { onClick(name) }
}
}
}
fun side1Run() {
// 创建一个 ComposeView, 可以通过声明式ui创建脚本界面
_composeView.create {
val header = mutableStateOf("Header")
val names = mutableStateListOf(_iterables.listOf("Alice", "Tom", "John"))
NamePicker(this, header, names) { name ->
// 点击时简单打印日志
_console.log(name)
}
}
// 启动一个Activity用于显示脚本界面
_activity.start()
}
//-m8test-remove side1Run();
import com.m8test.script.core.api.ui.compose.modifier.Modifier
import com.m8test.script.core.api.ui.compose.slot.Slot
import com.m8test.script.core.api.ui.compose.state.MutableState
import com.m8test.script.core.api.ui.compose.state.MutableStateList
/**
* 显示用户可以点击的带有标题的名称列表
*/
private static def NamePicker(Slot<? extends Modifier> slot, MutableState<String> header, MutableStateList<String> names, Closure<String> onNameClick) {
slot.Column { column ->
column.setContent { columnScopeSlot ->
columnScopeSlot.Text { text ->
// 当 [header] 发生改变时,它将被重新组合,但当 [names] 发生改变时,它将不会被重新组合
text.trackSingleState(header)
text.setText(header.getValue())
}
columnScopeSlot.HorizontalDivider {}
// LazyColumn 是 RecyclerView 的 Compose 版本。
// 传递给 items() 的 lambda 类似于 RecyclerView.ViewHolder
columnScopeSlot.LazyColumn { lazyColumn ->
lazyColumn.setContent { lazyListScope ->
lazyListScope.itemsIndexed(names, null, null) { lazyItemScopeSlot, index, name ->
// 当某个项目的 [name] 更新时,该项目的适配器将进行重组。当 [header] 更改时,此适配器不会进行重组
NamePickerItem(lazyItemScopeSlot, name, onNameClick)
}
}
}
}
}
}
/**
* 显示用户可以点击的单个名称。
*/
private static def NamePickerItem(Slot<? extends Modifier> slot, String name, Closure<String> onClick) {
slot.Text { text ->
text.setText(name)
text.setModifier { modifier ->
modifier.clickable(true, null, null) { onClick(name) }
}
}
}
// 创建一个 ComposeView, 可以通过声明式ui创建脚本界面
$composeView.create { slot ->
def header = slot.mutableStateOf("Header")
def names = slot.mutableStateListOf($iterables.listOf("Alice", "Tom", "John"))
NamePicker(slot, header, names, ({ name ->
// 点击时简单打印日志
$console.log(name)
} as Closure<String>))
}
// 启动一个Activity用于显示脚本界面
$activity.start()
/**
* 显示用户可以点击的带有标题的名称列表
* @param {object} slot
* @param {object} header
* @param {object} names
* @param {function(string): void} onNameClick
*/
function NamePicker(slot, header, names, onNameClick) {
slot.Column(column => {
column.setContent(columnScopeSlot => {
columnScopeSlot.Text(text => {
// 当 [header] 发生改变时,它将被重新组合,但当 [names] 发生改变时,它将不会被重新组合
text.trackSingleState(header);
text.setText(header.getValue());
});
columnScopeSlot.HorizontalDivider(() => {});
// LazyColumn 是 RecyclerView 的 Compose 版本。
// 传递给 items() 的 lambda 类似于 RecyclerView.ViewHolder
columnScopeSlot.LazyColumn(lazyColumn => {
lazyColumn.setContent(lazyListScope => {
lazyListScope.itemsIndexed(names, null, null, (lazyItemScopeSlot, index, name) => {
// 当某个项目的 [name] 更新时,该项目的适配器将进行重组。当 [header] 更改时,此适配器不会进行重组
NamePickerItem(lazyItemScopeSlot, name, onNameClick);
});
});
});
});
});
}
/**
* 显示用户可以点击的单个名称。
* @param {object} slot
* @param {string} name
* @param {function(string): void} onClick
*/
function NamePickerItem(slot, name, onClick) {
slot.Text(text => {
text.setText(name);
text.setModifier(modifier => {
modifier.clickable(true, null, null, () => onClick(name));
});
});
}
// 创建一个 ComposeView, 可以通过声明式ui创建脚本界面
$composeView.create(slot => {
const header = slot.mutableStateOf("Header");
const names = slot.mutableStateListOf($iterables.listOf("Alice", "Tom", "John"));
NamePicker(slot, header, names, name => {
// 点击时简单打印日志
$console.log(name);
});
});
// 启动一个Activity用于显示脚本界面
$activity.start();
--[[
* 显示用户可以点击的单个名称。
]]
local function NamePickerItem(slot, name, onClick)
slot:Text(function(text)
text:setText(name)
text:setModifier(function(modifier)
modifier:clickable(true, nil, nil, function()
onClick(name)
end)
end)
end)
end
--[[
* 显示用户可以点击的带有标题的名称列表
]]
local function NamePicker(slot, header, names, onNameClick)
slot:Column(function(column)
column:setContent(function(columnScopeSlot)
columnScopeSlot:Text(function(text)
-- 当 [header] 发生改变时,它将被重新组合,但当 [names] 发生改变时,它将不会被重新组合
text:trackSingleState(header)
text:setText(tostring(header:getValue()))
end)
columnScopeSlot:HorizontalDivider(function() end)
-- LazyColumn 是 RecyclerView 的 Compose 版本。
-- 传递给 items() 的 lambda 类似于 RecyclerView.ViewHolder
columnScopeSlot:LazyColumn(function(lazyColumn)
lazyColumn:setContent(function(lazyListScope)
lazyListScope:itemsIndexed(names, nil, nil, function(lazyItemScopeSlot, index, name)
-- 当某个项目的 [name] 更新时,该项目的适配器将进行重组。当 [header] 更改时,此适配器不会进行重组
NamePickerItem(lazyItemScopeSlot, name, onNameClick)
end)
end)
end)
end)
end)
end
-- 创建一个 ComposeView, 可以通过声明式ui创建脚本界面
_composeView:create(function(slot)
local header = slot:mutableStateOf("Header")
-- 假设 _iterables:listOf 存在,并接收一个 Lua table 来创建 Java List
local names = slot:mutableStateListOf(_iterables:listOf("Alice", "Tom", "John"))
NamePicker(slot, header, names, function(name)
-- 点击时简单打印日志
_console:log(name)
end)
end)
-- 启动一个Activity用于显示脚本界面
_activity:start()
<?php
use m8test_java\com\m8test\script\core\api\ui\compose\modifier\Modifier;
use m8test_java\com\m8test\script\core\api\ui\compose\slot\Slot;
use m8test_java\com\m8test\script\core\api\ui\compose\state\MutableState;
use m8test_java\com\m8test\script\core\api\ui\compose\state\MutableStateList;
/** @var m8test_java\com\m8test\script\core\api\ui\compose\ComposeView $composeView */
global $composeView;
/** @var m8test_java\com\m8test\script\core\api\ui\Activity $activity */
global $activity;
/** @var m8test_java\com\m8test\script\core\api\collections\Iterables $iterables */
global $iterables;
/** @var m8test_java\com\m8test\script\core\api\console\Console $console */
global $console;
/**
* 显示用户可以点击的单个名称。
* @param Slot $slot
*/
function NamePickerItem($slot, string $name, callable $onClick)
{
$slot->Text(function ($text) use ($name, $onClick) {
$text->setText($name);
$text->setModifier(function ($modifier) use ($name, $onClick) {
$modifier->clickable(true, null, null, function () use ($name, $onClick) {
$onClick($name);
});
});
});
}
/**
* 显示用户可以点击的带有标题的名称列表
* @param Slot $slot
*/
function NamePicker($slot, MutableState $header, MutableStateList $names, callable $onNameClick)
{
$slot->Column(function ($column) use ($header, $names, $onNameClick) {
$column->setContent(function ($columnScopeSlot) use ($header, $names, $onNameClick) {
$columnScopeSlot->Text(function ($text) use ($header) {
// 当 [header] 发生改变时,它将被重新组合,但当 [names] 发生改变时,它将不会被重新组合
$text->trackSingleState($header);
$text->setText($header->getValue());
});
$columnScopeSlot->HorizontalDivider(function () {
});
// LazyColumn 是 RecyclerView 的 Compose 版本。
// 传递给 items() 的 lambda 类似于 RecyclerView.ViewHolder
$columnScopeSlot->LazyColumn(function ($lazyColumn) use ($names, $onNameClick) {
$lazyColumn->setContent(function ($lazyListScope) use ($names, $onNameClick) {
$lazyListScope->itemsIndexed($names, null, null, function ($lazyItemScopeSlot, $index, $name) use ($onNameClick) {
// 当某个项目的 [name] 更新时,该项目的适配器将进行重组。当 [header] 更改时,此适配器不会进行重组
NamePickerItem($lazyItemScopeSlot, $name, $onNameClick);
});
});
});
});
});
}
// 创建一个 ComposeView, 可以通过声明式ui创建脚本界面
$composeView->create(function ($slot) {
global $iterables, $console;
$header = $slot->mutableStateOf(javaString("Header"));
$names = $slot->mutableStateListOf($iterables->listOf(javaString("Alice"), javaString("Tom"), javaString("John")));
NamePicker($slot, $header, $names, function ($name) {
global $console;
// 点击时简单打印日志
$console->log($name);
});
});
// 启动一个Activity用于显示脚本界面
$activity->start();
# 导入所需的全局变量
from m8test_java.com.m8test.script.GlobalVariables import _composeView
from m8test_java.com.m8test.script.GlobalVariables import _iterables
from m8test_java.com.m8test.script.GlobalVariables import _console
from m8test_java.com.m8test.script.GlobalVariables import _activity
# 导入所需的Java类
from m8test_java.com.m8test.script.core.api.ui.compose.modifier.Modifier import Modifier
from m8test_java.com.m8test.script.core.api.ui.compose.slot.Slot import Slot
from m8test_java.com.m8test.script.core.api.ui.compose.state.MutableState import MutableState
from m8test_java.com.m8test.script.core.api.ui.compose.state.MutableStateList import MutableStateList
def NamePicker(slot, header, names, onNameClick):
"""
显示用户可以点击的带有标题的名称列表
"""
slot.Column(lambda column: (
column.setContent(lambda columnScopeSlot: (
columnScopeSlot.Text(lambda text: (
# 当 [header] 发生改变时,它将被重新组合,但当 [names] 发生改变时,它将不会被重新组合
text.trackSingleState(header),
text.setText(header.getValue())
)),
# 修复:将 lambda: None 修改为 lambda _: None
# 框架会向此回调传递一个参数,即使我们用不到它,也必须定义一个形参来接收,否则会报TypeError
columnScopeSlot.HorizontalDivider(lambda _: None),
# LazyColumn 是 RecyclerView 的 Compose 版本。
# 传递给 items() 的 lambda 类似于 RecyclerView.ViewHolder
columnScopeSlot.LazyColumn(lambda lazyColumn: (
lazyColumn.setContent(lambda lazyListScope: (
lazyListScope.itemsIndexed(names, None, None, lambda lazyItemScopeSlot, index, name: (
# 当某个项目的 [name] 更新时,该项目的适配器将进行重组。当 [header] 更改时,此适配器不会进行重组
NamePickerItem(lazyItemScopeSlot, name, onNameClick)
))
))
))
))
))
def NamePickerItem(slot, name, onClick):
"""
显示用户可以点击的单个名称。
"""
slot.Text(lambda text: (
text.setText(name),
text.setModifier(lambda modifier: (
# Groovy的 { onClick(name) } 是一个无参闭包,它调用了外部的onClick函数
# 对应Python的 lambda: onClick(name)
modifier.clickable(True, None, None, lambda: onClick(name))
))
))
# 创建一个 ComposeView, 可以通过声明式ui创建脚本界面
_composeView.create(lambda slot: (
(header := slot.mutableStateOf("Header")),
(names := slot.mutableStateListOf(_iterables.listOf("Alice", "Tom", "John"))),
NamePicker(slot, header, names,
# Groovy的 ({ name -> ... } as Closure<String>) 直接变成Python的 lambda name: ...
# 点击时简单打印日志
lambda name: _console.log(name)
)
))
# 启动一个Activity用于显示脚本界面
_activity.start()
# encoding: utf-8
# 显示用户可以点击的带有标题的名称列表
# onNameClick 在 Ruby 中作为一个 Proc 对象传递
def NamePicker(slot, header, names, onNameClick)
slot.Column do |column|
column.setContent do |columnScopeSlot|
columnScopeSlot.Text do |text|
# 当 [header] 发生改变时,它将被重新组合,但当 [names] 发生改变时,它将不会被重新组合
text.trackSingleState(header)
text.setText(header.getValue())
end
columnScopeSlot.HorizontalDivider {}
# LazyColumn 是 RecyclerView 的 Compose 版本。
# 传递给 items() 的 lambda 类似于 RecyclerView.ViewHolder
columnScopeSlot.LazyColumn do |lazyColumn|
lazyColumn.setContent do |lazyListScope|
lazyListScope.itemsIndexed(names, nil, nil) do |lazyItemScopeSlot, index, name|
# 当某个项目的 [name] 更新时,该项目的适配器将进行重组。当 [header] 更改时,此适配器不会进行重组
NamePickerItem(lazyItemScopeSlot, name, onNameClick)
end
end
end
end
end
end
# 显示用户可以点击的单个名称。
def NamePickerItem(slot, name, onClick)
slot.Text do |text|
text.setText(name)
text.setModifier do |modifier|
modifier.clickable(true, nil, nil) { onClick.call(name) }
end
end
end
# 创建一个 ComposeView, 可以通过声明式ui创建脚本界面
$composeView.create do |slot|
header = slot.mutableStateOf("Header")
names = slot.mutableStateListOf($iterables.listOf("Alice", "Tom", "John"))
# 使用 lambda 或 proc 创建闭包传递
NamePicker(slot, header, names, lambda { |name|
# 点击时简单打印日志
$console.log(name)
})
end
# 启动一个Activity用于显示脚本界面
$activity.start()
这些作用域中的每一个都可能是在重组期间执行的唯一一个作用域。当 header 发生更改时,Compose 可能会跳至 Column lambda,而不执行它的任何父项。此外,执行 Column 时,如果 names 未更改,Compose 可能会选择跳过 LazyColumn 的项。