[go: nahoru, domu]

blob: 275d7b4b891d0784dc3c400138eb0c7ea32064c0 [file] [log] [blame]
/*
* Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.compose.material.demos
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.preferredHeight
import androidx.compose.foundation.layout.preferredWidth
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.selection.selectable
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Checkbox
import androidx.compose.material.ContentAlpha
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.OutlinedTextField
import androidx.compose.material.RadioButton
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.Info
import androidx.compose.material.samples.PasswordTextField
import androidx.compose.material.samples.SimpleOutlinedTextFieldSample
import androidx.compose.material.samples.TextFieldSample
import androidx.compose.material.samples.TextFieldWithErrorState
import androidx.compose.material.samples.TextFieldWithHelperMessage
import androidx.compose.material.samples.TextFieldWithHideKeyboardOnImeAction
import androidx.compose.material.samples.TextFieldWithIcons
import androidx.compose.material.samples.TextFieldWithPlaceholder
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
@Composable
fun TextFieldsDemo() {
LazyColumn(
modifier = Modifier.fillMaxHeight()
) {
item {
Text("Password text field")
PasswordTextField()
}
item {
Text("Text field with leading and trailing icons")
TextFieldWithIcons()
}
item {
Text("Outlined text field")
SimpleOutlinedTextFieldSample()
}
item {
Text("Text field with placeholder")
TextFieldWithPlaceholder()
}
item {
Text("Text field with error state handling")
TextFieldWithErrorState()
}
item {
Text("Text field with helper/error message")
TextFieldWithHelperMessage()
}
item {
Text("Hide keyboard on IME action")
TextFieldWithHideKeyboardOnImeAction()
}
item {
Text("TextFieldValue overload")
TextFieldSample()
}
}
}
@Composable
fun VerticalAlignmentsInTextField() {
Column {
val singleLine = remember { mutableStateOf(false) }
val label = remember { mutableStateOf(false) }
val text = remember { mutableStateOf("") }
Spacer(Modifier.height(10.dp))
OptionRow(
title = "Single line",
checked = singleLine.value,
onCheckedChange = { singleLine.value = it }
)
OptionRow(
title = "Label",
checked = label.value,
onCheckedChange = { label.value = it }
)
Spacer(Modifier.height(10.dp))
val textFieldModifier = Modifier
.align(Alignment.CenterHorizontally)
.width(300.dp)
.heightIn(max = 200.dp)
.then(if (singleLine.value) Modifier else Modifier.heightIn(min = 100.dp))
TextField(
value = text.value,
onValueChange = { text.value = it },
label = { if (label.value) Text("Label") },
singleLine = singleLine.value,
modifier = textFieldModifier
)
Spacer(Modifier.height(10.dp))
OutlinedTextField(
value = text.value,
onValueChange = { text.value = it },
label = { if (label.value) Text("Label") },
singleLine = singleLine.value,
modifier = textFieldModifier
)
}
}
@Composable
fun MaterialTextFieldDemo() {
Column(Modifier.verticalScroll(rememberScrollState()).padding(PaddingValues(10.dp))) {
var text by rememberSaveable { mutableStateOf("") }
var leadingChecked by rememberSaveable { mutableStateOf(false) }
var trailingChecked by rememberSaveable { mutableStateOf(false) }
val characterCounterChecked by rememberSaveable { mutableStateOf(false) }
var singleLineChecked by rememberSaveable { mutableStateOf(true) }
var selectedOption by rememberSaveable { mutableStateOf(Option.None) }
var selectedTextField by rememberSaveable { mutableStateOf(TextFieldType.Filled) }
var disabled by rememberSaveable { mutableStateOf(false) }
var readOnly by rememberSaveable { mutableStateOf(false) }
val textField: @Composable () -> Unit = @Composable {
when (selectedTextField) {
TextFieldType.Filled ->
TextField(
value = text,
onValueChange = { text = it },
enabled = !disabled,
readOnly = readOnly,
singleLine = singleLineChecked,
label = {
val label =
"Label" + if (selectedOption == Option.Error) "*" else ""
Text(text = label)
},
leadingIcon = {
if (leadingChecked) Icon(Icons.Filled.Favorite, "Favorite")
},
trailingIcon = {
if (trailingChecked) Icon(Icons.Filled.Info, "Info")
},
isErrorValue = selectedOption == Option.Error,
modifier = Modifier.width(300.dp)
)
TextFieldType.Outlined ->
OutlinedTextField(
value = text,
onValueChange = { text = it },
enabled = !disabled,
readOnly = readOnly,
singleLine = singleLineChecked,
label = {
val label =
"Label" + if (selectedOption == Option.Error) "*" else ""
Text(text = label)
},
leadingIcon = {
if (leadingChecked) Icon(Icons.Filled.Favorite, "Favorite")
},
trailingIcon = {
if (trailingChecked) Icon(Icons.Filled.Info, "Info")
},
isErrorValue = selectedOption == Option.Error,
modifier = Modifier.width(300.dp)
)
}
}
Box(Modifier.preferredHeight(150.dp).align(Alignment.CenterHorizontally)) {
if (selectedOption == Option.None) {
textField()
} else {
TextFieldWithMessage(selectedOption, textField)
}
}
Column {
Title("Text field type")
TextFieldType.values().map { it.name }.forEach { textType ->
Row(
Modifier
.fillMaxWidth()
.selectable(
selected = (textType == selectedTextField.name),
onClick = {
selectedTextField = TextFieldType.valueOf(textType)
}
)
.padding(horizontal = 16.dp)
) {
RadioButton(
selected = (textType == selectedTextField.name),
onClick = { selectedTextField = TextFieldType.valueOf(textType) }
)
Text(
text = textType,
style = MaterialTheme.typography.body1.merge(),
modifier = Modifier.padding(start = 16.dp)
)
}
}
Title("Options")
OptionRow(
title = "Leading icon",
checked = leadingChecked,
onCheckedChange = { leadingChecked = it }
)
OptionRow(
title = "Trailing icon",
checked = trailingChecked,
onCheckedChange = { trailingChecked = it }
)
OptionRow(
title = "Single line",
checked = singleLineChecked,
onCheckedChange = { singleLineChecked = it }
)
OptionRow(
title = "Character counter (TODO)",
checked = characterCounterChecked,
enabled = false,
onCheckedChange = { /* TODO */ }
)
Spacer(Modifier.preferredHeight(20.dp))
Title("Assistive text")
Option.values().map { it.name }.forEach { text ->
Row(
Modifier
.fillMaxWidth()
.selectable(
selected = (text == selectedOption.name),
onClick = { selectedOption = Option.valueOf(text) }
)
.padding(horizontal = 16.dp)
) {
RadioButton(
selected = (text == selectedOption.name),
onClick = { selectedOption = Option.valueOf(text) }
)
Text(
text = text,
style = MaterialTheme.typography.body1.merge(),
modifier = Modifier.padding(start = 16.dp)
)
}
}
Title("Other settings")
OptionRow(
title = "Read-only",
checked = readOnly,
onCheckedChange = { readOnly = it }
)
OptionRow(
title = "Disabled",
checked = disabled,
onCheckedChange = { disabled = it }
)
}
}
}
/**
* Text field with helper or error message below.
*/
@Composable
private fun TextFieldWithMessage(
helperMessageOption: Option,
content: @Composable () -> Unit
) {
val typography = MaterialTheme.typography.caption
val color = when (helperMessageOption) {
Option.Helper -> {
MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.medium)
}
Option.Error -> MaterialTheme.colors.error
else -> Color.Unspecified
}
Column {
Box(modifier = Modifier.weight(1f, fill = false)) { content() }
Text(
text = "Helper message",
color = color,
style = typography,
modifier = Modifier.padding(start = 16.dp)
)
}
}
@Composable
private fun ColumnScope.Title(title: String) {
Text(
text = title,
style = MaterialTheme.typography.body1,
modifier = Modifier.align(Alignment.CenterHorizontally)
)
Spacer(Modifier.preferredHeight(10.dp))
}
@Composable
private fun OptionRow(
title: String,
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
enabled: Boolean = true
) {
Row(Modifier.padding(start = 10.dp, top = 10.dp)) {
Checkbox(checked = checked, onCheckedChange = onCheckedChange, enabled = enabled)
Spacer(Modifier.preferredWidth(20.dp))
Text(text = title, style = MaterialTheme.typography.body1)
}
}
/**
* Helper message option
*/
private enum class Option { None, Helper, Error }
private enum class TextFieldType { Filled, Outlined }