首页 安卓& Kotlin Books Jetpack由教程组成

8
应用材料设计来撰写 由Denis Buketa撰写

做得好!您已到达本节的最后一章。到目前为止在您的旅程中,您已经了解了撰写的基本兼容性,以及如何在您必须管理状态的真实应用程序中组合,样式和使用它们。

在本章中,您将:

  • 学习如何使用 材料设计兼容,哪个Jetpack组成为您提供。
  • 过去 国家管理层 in more depth.
  • 完成 保存 screen.
  • 学习关于 材料主题.
  • 改变 JetNotes. 支持A. 黑暗主题.

完成本章后, JetNotes. 将是一个全功能的应用程序!

打开笔记屏幕

在开始工作之前 保存 屏幕,您需要一种方法来打开它。通过查看设计,您可以看到您已计划两种方法来做到这一点:

  1. 单击浮动动作按钮(Fab),将打开 保存 屏幕 创建 模式,用户创建一个新的音符。
  2. 点击任何笔记 笔记 屏幕,打开它 编辑 模式,用户可以编辑该特定注释。

你将从第一个案例开始。但是,在添加浮动动作按钮之前 笔记 屏幕,您需要添加一些 布局结构 to it.

注意屏幕
注意屏幕

花点时间查看屏幕的不同部分。你有:

  • 顶酒吧
  • 身体内容
  • 浮动动作按钮
  • App抽屉

This is a common layout structure for Android apps. Most apps today follow a similar design. To make it easier to implement a layout structure like this, Jetpack组成提供 the Scaffold.

Before going into any details, you’ll add a Scaffold to the 笔记 screen.

添加脚手架

要与代码示例一起,请打开本章 初学项目 在Android Studio并选择 打开现有项目.

@Composable
fun NotesScreen(viewModel: MainViewModel) {

  // Observing notes state from MainViewModel
  ...

  Scaffold(
    topBar = {
      TopAppBar(
        title= "JetNotes.",
        icon = Icons.Filled.List,
        onIconClick = {}
      )
    },
    bodyContent = {
      if (notes.isNotEmpty()) {
        NotesList(
          notes = notes,
          onNoteCheckedChange = { 
          	viewModel.onNoteCheckedChange(it) 
          },
          onNoteClick = { viewModel.onNoteClick(it) }
        )
      }
    }
  )
}
import androidx.compose.material.Scaffold
注意屏幕
Cumer HXMAIX.

@Composable 
fun Scaffold(
  modifier: Modifier = Modifier,
  scaffoldState: ScaffoldState = rememberScaffoldState(),
  topBar: @Composable () -> Unit = emptyContent(), // Top Bar
  bottomBar: @Composable () -> Unit = emptyContent(), // Bottom Bar
  snackbarHost: @Composable (SnackbarHostState) -> Unit = { SnackbarHost(it) },
  floatingActionButton: @Composable () -> Unit = emptyContent(), // FAB
  floatingActionButtonPosition: FabPosition = FabPosition.End,
  isFloatingActionButtonDocked: Boolean = false,
  drawerContent: @Composable (ColumnScope.() -> Unit)? = null, // Navigation Drawer
  drawerGesturesEnabled: Boolean = true,
  drawerShape: Shape = MaterialTheme.shapes.large,
  drawerElevation: Dp = DrawerConstants.DefaultElevation,
  drawerBackgroundColor: Color = MaterialTheme.colors.surface,
  drawerContentColor: Color = contentColorFor(drawerBackgroundColor),
  drawerScrimColor: Color = DrawerConstants.defaultScrimColor,
  backgroundColor: Color = MaterialTheme.colors.background,
  contentColor: Color = contentColorFor(backgroundColor),
  bodyContent: @Composable (PaddingValues) -> Unit // Screen Content
)

恢复应用程序抽屉

在上一章中,您暂时从应用程序抽屉中删除了应用程序抽屉 笔记 屏幕。现在,现在是时候恢复了,略微改善了。

@Composable
fun NotesScreen(viewModel: MainViewModel) {

  // Observing notes state from MainViewModel
  ...

  // here - Drawer state
  val scaffoldState: ScaffoldState = rememberScaffoldState()

  Scaffold(
    topBar = {
      TopAppBar(
        title= "JetNotes.",
        icon = Icons.Filled.List,
        onIconClick = { 
          // here - Drawer open
          scaffoldState.drawerState.open() 
        }
      )
    },
    scaffoldState = scaffoldState, // here - Scaffold state
    drawerContent = { // here - Drawer UI
      AppDrawer(
        currentScreen = Screen.Notes,
        closeDrawerAction = { 
          // here - Drawer close
          scaffoldState.drawerState.close()
        }
      )
    },
    ...
  )
}
import androidx.compose.material.ScaffoldState
import androidx.compose.material.rememberScaffoldState
import com.raywenderlich.android.jetnotes.routing.Screen
import com.raywenderlich.android.jetnotes.ui.components.AppDrawer
注意屏幕和应用程序抽屉
Qodeq Gmabaip申请kdonol

可组合功能中的内存

Scaffold() can manage two composables that have state: app drawer and snackbar. Their states, DrawerStateSnackbarHostState, are encapsulated in one object called ScaffoldState.

使用记住

Here’s how remember() looks in code:

@Composable
fun <T> remember(calculation: () -> T): T
@Composable
fun rememberScaffoldState(
  drawerState: DrawerState = rememberDrawerState(
    DrawerValue.Closed
  ), 
  snackbarHostState: SnackbarHostState = remember { 
    SnackbarHostState() 
  }
): ScaffoldState
@Composable
fun rememberDrawerState(
    initialValue: DrawerValue,
    confirmStateChange: (DrawerValue) -> Boolean = { true }
): DrawerState {
  val clock = AmbientAnimationClock.current.asDisposableClock()
  return rememberSavedInstanceState(
    clock,
    saver = DrawerState.Saver(clock, confirmStateChange)
  ) {
    DrawerState(initialValue, clock, confirmStateChange)
  }
}

请记住对成分树的影响

Here’s how the composition tree looks for 笔记Screen().

注意屏幕 - 构图树
setab ksdiil - yiwomoyoor shaa

添加工厂

A 浮动动作按钮 表示屏幕的主要操作。在里面 笔记 屏幕,主要操作是创建新注释的操作。

@Composable
fun NotesScreen(viewModel: MainViewModel) {

  // Observing notes state from MainViewModel
  ...

  val scaffoldState: ScaffoldState = rememberScaffoldState()

  Scaffold(
    ...,
    floatingActionButtonPosition = FabPosition.End,
    floatingActionButton = {
      FloatingActionButton(
          onClick = { viewModel.onCreateNewNoteClick() },
          contentColor = MaterialTheme.colors.background,
          content = { Icon(Icons.Filled.Add) }
      )
    },
    ...
  )
}
import androidx.compose.material.*
import androidx.compose.material.icons.filled.Add
带浮动动作按钮的注意屏幕
Xuqim Qtqaus Pokr Jrausalw Agnuid Gitsem

添加一个入口点

在上一节中,您添加了允许您打开的工厂 保存 屏幕在创建模式下。

@Composable
fun SaveNoteScreen(viewModel: MainViewModel) {

}
import com.raywenderlich.android.jetnotes.viewmodel.MainViewModel

使用JetNotesRouter更改屏幕

在上一章中,您添加了打开的代码 笔记 screen whenever you start MainActivity. It’s time to add logic to change screens with JetNotes.Router.

@Composable
private fun MainActivityScreen(viewModel: MainViewModel) {
  Surface {
    when (JetNotesRouter.currentScreen) {
      is Screen.Notes -> NotesScreen(viewModel)
      is Screen.SaveNote -> SaveNoteScreen(viewModel)
      is Screen.Trash -> TrashScreen(viewModel)
    }
  }
}
import androidx.compose.material.Surface
import androidx.compose.runtime.Composable
import com.raywenderlich.android.jetnotes.routing.JetNotesRouter
import com.raywenderlich.android.jetnotes.routing.Screen
import com.raywenderlich.android.jetnotes.ui.screens.SaveNoteScreen
import com.raywenderlich.android.jetnotes.ui.screens.TrashScreen

将可组合的合作连接到主动

Next, you’ll connect this composable to MainActivity. Update setContent() in the MainActivity:

class MainActivity : AppCompatActivity() {

  ...

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    setContent {
      JetNotesTheme {
        MainActivityScreen(viewModel = viewModel) // here
      }
    }
  }
}

调用JetnotesRouter.

打开 mainviewModel.kt. 和 update onCreateNewNoteClick():

class MainViewModel(private val repository: Repository) : ViewModel() {

  ...

  fun onCreateNewNoteClick() {
    JetNotesRouter.navigateTo(Screen.SaveNote)
  }

  ...
}
import com.raywenderlich.android.jetnotes.routing.JetNotesRouter
import com.raywenderlich.android.jetnotes.routing.Screen
打开保存备注屏幕
AQICUKD XAFA JEJIZ MSWIEL

添加顶栏

到目前为止,您已专注于添加代码以打开 保存 屏幕。但现在你可以打开它, 保存 屏幕是空的。在本节中,您将添加兼容性物品。 :]

@Composable
fun SaveNoteScreen(viewModel: MainViewModel) {
  Scaffold(
    topBar = {},
    bodyContent = {}
  )
}
import androidx.compose.material.Scaffold
保存说明屏幕:顶级栏
Koti Sayu nvnaop:Toz Gug

添加savenoteTopAppBar.

在里面 保存 屏幕,顶部条需要支持两种不同的模式:

@Composable
private fun SaveNoteTopAppBar(
  isEditingMode: Boolean,
  onBackClick: () -> Unit,
  onSaveNoteClick: () -> Unit,
  onOpenColorPickerClick: () -> Unit,
  onDeleteNoteClick: () -> Unit
) {

}

显示顶杆

既然您为顶级栏准备了根的Composable,您将添加发出UI中顶栏的可组合物。

TopAppBar(
  title= {
    Text(
      text = "保存",
      color = MaterialTheme.colors.onPrimary
    )
  }
)
navigationIcon = {
  IconButton(onClick = onBackClick) {
    Icon(imageVector = Icons.Filled.ArrowBack)
  }
}
actions = {
  // Save note action icon
  IconButton(onClick = onSaveNoteClick) {
    Icon(
      imageVector = Icons.Default.Check,
      tint = MaterialTheme.colors.onPrimary
    )
  }

  // Open color picker action icon
  IconButton(onClick = onOpenColorPickerClick) {
    Icon(
      imageVector = vectorResource(
        id = R.drawable.ic_baseline_color_lens_24
      ),
      tint = MaterialTheme.colors.onPrimary
    )
  }
}
// Delete action icon (show only in editing mode)
if (isEditingMode) {
  IconButton(onClick = onDeleteNoteClick) {
    Icon(
      imageVector = Icons.Default.Delete,
      tint = MaterialTheme.colors.onPrimary
    )
  }
}
import androidx.compose.material.*
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.TopAppBar
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.Delete
import androidx.compose.ui.res.vectorResource
import com.raywenderlich.android.jetnotes.R
@Preview
@Composable
fun SaveNoteTopAppBarPreview() {
  SaveNoteTopAppBar(
    isEditingMode = true,
    onBackClick = {},
    onSaveNoteClick = {},
    onOpenColorPickerClick = {},
    onDeleteNoteClick = {}
  )
}
SavenoteTopAppBar可组合(编辑模式) - 预览
Bujuwidixumapjkuw Rahluwuwle(Umerujukq Doqe) - Bniwiol

SaveNoteTopAppBar可组合(新注释模式) - 预览
Zokepiroroqaxvmow Xalgamoyme(Wij Rowe Mexe) - Vyiqaud

显示SavenoteTopAppBar可组合的

Now that you’ve created the SaveNoteTopAppBar(), you can display it in the 保存 屏幕。但在你这样做之前,你需要一种知道用户是否打开的方式 保存 屏幕为新的音符或现有的音符。

private var _noteEntry = MutableLiveData(NoteModel())
val noteEntry: LiveData<NoteModel> = _noteEntry
@Composable
fun SaveNoteScreen(viewModel: MainViewModel) {

  val noteEntry: NoteModel by viewModel.noteEntry
    .observeAsState(NoteModel())

  Scaffold(
    topBar = {
      val isEditingMode: Boolean = noteEntry.id != NEW_NOTE_ID
      SaveNoteTopAppBar(
        isEditingMode = isEditingMode,
        onBackClick = { 
          JetNotesRouter.navigateTo(Screen.Notes) 
        },
        onSaveNoteClick = { },
        onOpenColorPickerClick = { },
        onDeleteNoteClick = { }
      )
    },
    bodyContent = {}
  )
}
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import com.raywenderlich.android.jetnotes.domain.model.NEW_NOTE_ID
import com.raywenderlich.android.jetnotes.domain.model.NoteModel
import com.raywenderlich.android.jetnotes.routing.JetNotesRouter
import com.raywenderlich.android.jetnotes.routing.Screen
将顶部栏添加到保存注意屏幕
Upxohv Hbe Fon Gub Bu Zki Sota Ruyo Dltius

在编辑模式下打开保存笔记屏幕

在上一节中,您实现了一种方式来打开 保存 屏幕在创建模式下。现在,您将添加允许用户编辑现有音符的逻辑。

fun onCreateNewNoteClick() {
  _noteEntry.value = NoteModel()
  JetNotesRouter.navigateTo(Screen.SaveNote)
}

fun onNoteClick(note: NoteModel) {
  _noteEntry.value = note
  JetNotesRouter.navigateTo(Screen.SaveNote)
}
在编辑模式下保存注意屏幕
Leye Yaxu Hzceok Ug Esoy Somu

创建内容可组合

您需要能够编辑注释 保存 屏幕,所以你的下一步是创建一个组合可以让你这样做的内容。

显示所选颜色

这样做,去 savenotescreen.kt. 和 add the following composable below SaveNoteTopAppBar():

@Composable
private fun PickedColor(color: ColorModel) {
  Row(
    Modifier
      .padding(8.dp)
      .padding(top = 16.dp)
  ) {
    Text(
      text = "Picked color",
      modifier = Modifier
        .weight(1f)
        .align(Alignment.CenterVertically)
    )
    NoteColor(
      color = Color.fromHex(color.hex),
      size = 40.dp,
      border = 1.dp,
      modifier = Modifier.padding(4.dp)
    )
  }
}
@Preview
@Composable
fun PickedColorPreview() {
  PickedColor(ColorModel.DEFAULT)
}
挑选 - 预览
Dontostuvaknadvatofc Wapgewapmu - 菲律宾

让用户检查一下音符

例如,在某些情况下,您的用户可能需要查看注释 - 例如,完成任务时。默认情况下,没有选项表示已完成注释。如果他们想要该功能,用户需要将注释标记为可选择。你的下一步是给他们那种可能性。

@Composable
private fun NoteCheckOption(
  isChecked: Boolean,
  onCheckedChange: (Boolean) -> Unit
) {
  Row(
    Modifier
      .padding(8.dp)
      .padding(top = 16.dp)
  ) {
    Text(
      text = "Can note be checked off?",
      modifier = Modifier.weight(1f)
    )
    Switch(
      checked = isChecked,
      onCheckedChange = onCheckedChange,
      modifier = Modifier.padding(start = 8.dp)
    )
  }
}
import androidx.compose.material.Switch
@Preview
@Composable
fun NoteCheckOptionPreview() {
  NoteCheckOption(false) {}
}
canbecheckedoffcomponent composable  - 预览
Fuwgugbevbucevxqolrolums Dudsibovca - Zkarous

添加标题和内容

到目前为止,您已添加兼容组件以表示注释的颜色以及用户是否可以在完成任务时检查注意事项。但您仍然必须为注释最重要的部分添加兼容组件:其标题和内容。

@Composable
private fun ContentTextField(
  modifier: Modifier = Modifier,
  label: String,
  text: String,
  onTextChange: (String) -> Unit
) {
  TextField(
    value = text,
    onValueChange = onTextChange,
    label = { Text(label) },
    modifier = modifier
      .fillMaxWidth()
      .padding(horizontal = 8.dp),
    backgroundColor = MaterialTheme.colors.surface
  )
}
@Preview
@Composable
fun ContentTextFieldPreview() {
  ContentTextField(
    label = "Title", 
    text = "", 
    onTextChange = {}
  )
}
ContentTextField CompoSable  - 预览
miwnigxnidrzuugt tojxohipdu - 追逐

构建保存注意内容

下一件事就是把你创造的所有糖果组合在一起 保存 screen content.

@Composable
private fun SaveNoteContent(
  note: NoteModel,
  onNoteChange: (NoteModel) -> Unit
) {
  Column(modifier = Modifier.fillMaxSize()) {

  }
}
ContentTextField(
  label = "Title",
  text = note.title,
  onTextChange = { newTitle ->
    onNoteChange.invoke(note.copy(title= newTitle))
  }
)

ContentTextField(
  modifier = Modifier
    .heightIn(max = 240.dp)
    .padding(top = 16.dp),
  label = "Body",
  text = note.content,
  onTextChange = { newContent ->
    onNoteChange.invoke(note.copy(content = newContent))
  }
)
val canBeCheckedOff: Boolean = note.isCheckedOff != null

NoteCheckOption(
  isChecked = canBeCheckedOff,
  onCheckedChange = { canBeCheckedOffNewValue ->
    val isCheckedOff: Boolean? = if (canBeCheckedOffNewValue) false else null
    
    onNoteChange.invoke(note.copy(isCheckedOff = isCheckedOff))
  }
)

PickedColor(color = note.color)
import androidx.compose.material.*
@Preview
@Composable
fun SaveNoteContentPreview() {
  SaveNoteContent(
    note = NoteModel(title= "Title", content = "content"),
    onNoteChange = {}
  )
}
内容可组合 - 预览
JEVQISL YALCASUYWA - GJOWEIX

包装保存注意屏幕

到目前为止很棒!在您完成UI的情况下,您只有一步一步 保存 屏幕。 You’ll now focus on MainViewModel, which you need to complete the 保存 screen.

添加ViewModel支持

In MainViewModel, you already added the code to expose the noteEntry state, but you still need to add one more state. In the 保存 screen, the user can choose a color for a note. To display the list of colors the user can choose, you need to provide them to SaveNoteScreen().

val colors: LiveData<List<ColorModel>> by lazy { 
  repository.getAllColors() 
}
import com.raywenderlich.android.jetnotes.domain.model.ColorModel

改变注意事项状态

Next, you need to add support for changing the noteEntry state when the user interacts with the 保存 screen.

fun onNoteEntryChange(note: NoteModel) {
  _noteEntry.value = note
}

fun saveNote(note: NoteModel) {
  viewModelScope.launch(Dispatchers.Default) {
    repository.insertNote(note)

    withContext(Dispatchers.Main) {
      JetNotesRouter.navigateTo(Screen.Notes)

      _noteEntry.value = NoteModel()
    }
  }
}

fun moveNoteToTrash(note: NoteModel) {
  viewModelScope.launch(Dispatchers.Default) {
    repository.moveNoteToTrash(note.id)

    withContext(Dispatchers.Main) { 
      JetNotesRouter.navigateTo(Screen.Notes) 
    }
  }
}

将SaveNotescreen连接到MainViewModel

Now that MainViewModel is ready, you can complete the UI part of the 保存 screen.

Scaffold(
  topBar = {
    val isEditingMode: Boolean = noteEntry.id != NEW_NOTE_ID
    SaveNoteTopAppBar(
      isEditingMode = isEditingMode,
      onBackClick = { 
        JetNotesRouter.navigateTo(Screen.Notes) 
      },
      onSaveNoteClick = { viewModel.saveNote(noteEntry) },
      onOpenColorPickerClick = { },
      onDeleteNoteClick = { 
        viewModel.moveNoteToTrash(noteEntry) 
      }
    )
  },
  bodyContent = { // here
    SaveNoteContent(
      note = noteEntry,
      onNoteChange = { updateNoteEntry ->
        viewModel.onNoteEntryChange(updateNoteEntry)
      }
    )
  }
)
保存注意屏幕
爱Qoxu thmiiv.

改变笔记的颜色

There is still one thing missing: You still can’t change the color of the notes. To fix that, update SaveNoteScreen() like this:

@Composable
fun SaveNoteScreen(viewModel: MainViewModel) {

  ...

  val colors: List<ColorModel> by viewModel.colors
    .observeAsState(listOf())

  val bottomDrawerState: BottomDrawerState =
    rememberBottomDrawerState(BottomDrawerValue.Closed)

  Scaffold(
    topBar = {
      val isEditingMode: Boolean = noteEntry.id != NEW_NOTE_ID
      SaveNoteTopAppBar(
        ...,
        onOpenColorPickerClick = { bottomDrawerState.open() },
        ...
      )
    },
    bodyContent = {
      BottomDrawerLayout(
        drawerState = bottomDrawerState,
        drawerContent = {
          ColorPicker(
            colors = colors,
            onColorSelect = { color ->
              val newNoteEntry = noteEntry.copy(color = color)
              viewModel.onNoteEntryChange(newNoteEntry)
            }
          )
        },
        bodyContent = {
          SaveNoteContent(
            note = noteEntry,
            onNoteChange = { updateNoteEntry ->
              viewModel.onNoteEntryChange(updateNoteEntry)
            }
          )
        }
      )
    }
  )
}
保存笔记屏幕上的彩色选择器
Tedoz nofveb ep vuna vobo twjius

确认删除操作

虽然这一点 保存 屏幕现在正常工作,要注意细节总是很好。

val moveNoteToTrashDialogShownState: MutableState<Boolean> = savedInstanceState { false }
SaveNoteTopAppBar(
  ...,
  onDeleteNoteClick = { 
    moveNoteToTrashDialogShownState.value = true 
  }
)
Scaffold(
  topBar = { ... },
  bodyContent = {
    BottomDrawerLayout(...)

    if (moveNoteToTrashDialogShownState.value) {
      AlertDialog(
        onDismissRequest = { 
          moveNoteToTrashDialogShownState.value = false 
        },
        title= {
          Text("Move note to the trash?")
        },
        text = { 
          Text(
            "Are you sure you want to " +
                "move this note to the trash?"
          ) 
        },
        confirmButton = {
          TextButton(onClick = {
            viewModel.moveNoteToTrash(noteEntry)
          }) {
            Text("Confirm")
          }
        },
        dismissButton = {
          TextButton(onClick = {
            moveNoteToTrashDialogShownState.value = false
          }) {
            Text("Dismiss")
          }
        }
      )
    }
  }
)
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.savedinstancestate.savedInstanceState
保存注意屏幕中的警报对话框
Epebz Piolux Ih Paci Gupo Lhjiis

添加支持按钮的支持

目前,当你打开时 保存 屏幕并按 后退 按钮,应用程序关闭。由于您不使用在后面堆叠上运行的活动或片段并在内部处理基本系统导航,因此如果用户按下系统回按钮,则需要处理您的应用程序的行为。

setContent {
  Providers(BackPressedDispatcher provides this) {
    JetNotesTheme {
      MainActivityScreen(viewModel = viewModel)
    }
  }
}
import androidx.compose.runtime.Providers
import com.raywenderlich.android.jetnotes.util.BackPressedDispatcher
后退PressHandler(onBackPressed = {
  if (bottomDrawerState.isOpen) {
    bottomDrawerState.close()
  } else {
    JetNotesRouter.navigateTo(Screen.Notes)
  }
})
import com.raywenderlich.android.jetnotes.util.BackPressHandler

在Notes屏幕中使用材料设计兼容性

Jetpack Compose提供的材料设计组合物都是通过基本组件构建的。当你建造的时候 笔记 屏幕,您以同样的方式实现了顶级App Bar和笔记卡。但由于材料设计兼容性为主题提供了额外的支持,因此替换使用材料设计构建的组件非常有用。

Scaffold(
  topBar = {
    TopAppBar(
      title= {
        Text(
          text = "JetNotes.",
          color = MaterialTheme.colors.onPrimary
        )
      },
      navigationIcon = {
        IconButton(onClick = {
          scaffoldState.drawerState.open()
        }) {
          Icon(imageVector = Icons.Filled.List)
        }
      }
    )
  },
...
)
import androidx.compose.material.TopAppBar

使用可组合物的材料

There’s one more thing you can replace with 材料设计兼容: your Note().

Card(
  shape = RoundedCornerShape(4.dp),
  modifier = Modifier
    .padding(8.dp)
    .fillMaxWidth(),
  backgroundColor = MaterialTheme.colors.surface
) {
  ListItem(
    text = { Text(text = note.title, maxLines = 1) },
    secondaryText = { Text(text = note.content, maxLines = 1) },
    icon = {
      NoteColor(
        color = Color.fromHex(note.color.hex),
        size = 40.dp,
        border = 1.dp
      )
    },
    trailing = {
      if (note.isCheckedOff != null) {
        Checkbox(
          checked = note.isCheckedOff,
          onCheckedChange = { isChecked ->
            val newNote = note.copy(isCheckedOff = isChecked)
            onNoteCheckedChange.invoke(newNote)
          },
          modifier = Modifier.padding(start = 8.dp)
        )
      }
    },
    modifier = Modifier.clickable { onNoteClick.invoke(note) })
}
import androidx.compose.material.Card
import androidx.compose.material.ListItem
import androidx.compose.material.*

撰写撰写

每个Android应用程序都有特定的调色板,排版和形状。 JetPack Compose提供了材料设计系统的实现,可以轻松指定应用程序的主题选择。

private val LightThemeColors = lightColors(
  primary = rwGreen,
  primaryVariant = rwGreenDark,
  secondary = rwRed
)

private val DarkThemeColors = lightColors(
  primary = rwGreen,
  primaryVariant = rwGreenDark,
  secondary = rwRed
)

@Composable
fun JetNotesTheme(content: @Composable () -> Unit) {
  val isDarkThemeEnabled = 
    isSystemInDarkTheme() || JetNotesThemeSettings.isDarkThemeEnabled
  
  val colors = if (isDarkThemeEnabled) DarkThemeColors else LightThemeColors

  MaterialTheme(colors = colors, content = content)
}
private val DarkThemeColors = darkColors(
  primary = Color(0xFF00A055),
  primaryVariant = Color(0xFF00F884),
  secondary = rwRed,
  onPrimary = Color.White,
)
import androidx.compose.material.darkColors
import androidx.compose.ui.graphics.Color
黑暗主题
Vukk Jbigu.

关键点

  • Jetpack组成提供 兼容 这使得很容易遵循 材料设计.
  • With remember(), Compose lets you 存储成分树中的值.
  • Using the OnBackPressedDispatcherOwner 和 providing it through an 周围的,您可以访问系统返回按钮处理。
  • Jetpack Compose提供了一种材料设计实现,可以通过指定来源您的应用程序 调色板, 排版形状.
  • Using MaterialTheme(), you define a theme for your app, that customizes colors, typography and shapes.
  • To define light and dark colors for different themes, you use lightColors()darkColors(), respectively.

然后去哪儿?

希望这对你来说是一个有趣的骑行。您已经走了很长的路,从使用只使用基本兼容性来管理具有材料设计兼容性的状态。在下一节中,您将在更复杂的应用程序上工作, jetreddit.!!在那里,您可以了解如何建立复杂的UI,动画如何工作等等。

有一个技术问题?想报告一个错误吗? 您可以向官方书籍论坛中的书籍作者提出问题和报告错误 这里.

有反馈分享在线阅读体验吗? 如果您有关于UI,UX的反馈,请高在线到设计团队:

© 2021 Razeware LLC

您可以免费读取,本章的部分显示为 混淆了 文本。解锁这本书,以及我们整个书籍和视频目录,带有Raywenderlich.com的专业订阅。

现在解锁

要突出或记笔记,您需要在订阅中拥有这本书或自行购买。