I am using version 1.1.0-alpha05 of Jetpack Compose and I wanted to know if there is a way to turn off the scrolling effect for LazyColumn like xml (android:overScrollMode="never")?
You can disable it by providing LocalOverscrollConfiguration:
CompositionLocalProvider(
LocalOverscrollConfiguration provides null
) {
LazyColumn(Modifier.fillMaxWidth()) {
items(1000) {
Text(it.toString())
}
}
}
You can also build it into your theme so that it applies to the entire application:
#Composable
fun AppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: #Composable () -> Unit
) {
val colors = if (darkTheme) {
DarkThemeColors
} else {
LightThemeColors
}
MaterialTheme(
colors = colors,
typography = typography,
shapes = shapes,
) {
CompositionLocalProvider(
LocalOverscrollConfiguration provides null,
content = content
)
}
}
p.s. in 1.2.0-rc01 LocalOverScrollConfiguration has being renamed to LocalOverscrollConfiguration
Related
In LazyColumn when we use LazyListScope.items with Surface. Inside multiple items there is extra padding on TOP and BOTTOM. I want to remove this padding. I am using Surface component of Material 3. BOM version is compose_bom = "2022.11.00".
Please don't suggest any alpha or beta version fix. If Material 3 stable api don't have solution, then please suggest normal Surface Material.
PreviewCreateListView
#Preview(showBackground = true)
#Composable
fun PreviewCreateListView() {
CreateListView()
}
CreateListView
#OptIn(ExperimentalMaterial3Api::class)
#Composable
fun CreateListView() {
val itemList = listOf(1, 2, 3)
LazyColumn(
contentPadding = PaddingValues(16.dp),
) {
items(itemList) { item ->
Surface(
onClick = { },
color = Color.Blue
) {
Text(
modifier = Modifier.fillMaxWidth(),
text = "$item",
)
}
}
}
}
Output
The M3 Surface with the onClick parameter has a minimum touch target size (48.dp) for accessibility. It will include extra space outside the component to ensure that they are accessible.
You can override this behaviour applying false to the LocalMinimumInteractiveComponentEnforcement. If it is set to false there will be no extra space.
Something like:
CompositionLocalProvider(
LocalMinimumInteractiveComponentEnforcement provides false) {
Surface(
onClick = { },
color = Color.Blue
) {
Text(
modifier = Modifier.fillMaxWidth(),
text = "$item",
)
}
}
Note: LocalMinimumInteractiveComponentEnforcement requires at least
M2 1.4.0-alpha04 and M3 1.1.0-alpha04. Before you can use LocalMinimumTouchTargetEnforcement in the same way.
The Surface variant that you use, with a onClick parameter, enforces a minimum height for accessibility purposes, see this at line 221
If you want to remove the space, use the variant without the onClick argument and use a Modifier.clickable instead
#Composable
fun CreateListView() {
val itemList = listOf(1, 2, 3)
LazyColumn(
contentPadding = PaddingValues(16.dp),
) {
items(itemList) { item ->
Surface(
modifier = Modifier.clickable { },
color = Color.Blue
) {
Text(
modifier = Modifier.fillMaxWidth(),
text = "$item",
)
}
}
}
}
I want to select all the characters in the text field when the text field is shown on the screen. When passing the same index like TextRange(2,2) it works fine but when using a different index like TextRange(0, name.length)), the selection is not working. I have mentioned the function below
#Composable
fun TestFunction(name: String) {
var fieldValue by remember {
mutableStateOf(TextFieldValue(name, selection = TextRange(0, name.length)))
}
val focusRequester by remember {
mutableStateOf(FocusRequester())
}
DisposableEffect(Unit) {
focusRequester.requestFocus()
onDispose { }
}
BasicTextField(
value = fieldValue,
onValueChange = { fieldValue = it },
modifier = Modifier.focusRequester(focusRequester),
)
}
Selection color depends on primary and background colors from your theme. You can see it in the source code of rememberTextSelectionColors which is used internally.
So if you can't see selection, that's probably because of your theme.
Check out how you can override this value without modifying your theme in this answer. To make it work for whole app you can embed this CompositionLocalProvider to your theme, like this:
#Composable
fun AppTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: #Composable() () -> Unit) {
val colors = if (darkTheme) {
DarkThemeColors
} else {
LightThemeColors
}
val customTextSelectionColors = TextSelectionColors(
handleColor = Color.Red,
backgroundColor = Color.Red.copy(alpha = 0.4f)
)
MaterialTheme(
colors = colors,
typography = typography,
shapes = shapes,
) {
CompositionLocalProvider(
LocalTextSelectionColors provides customTextSelectionColors,
content = content,
)
}
}
I want to set a direction of a specific composable to be RTL
#Composable
fun ViewToBeChanged() {
Row {
Image()
Column {
Text("Title")
Text("Subtitle")
}
}
}
Is it possible?
Jetpack compose Layout documentation mentions LocalLayoutDirection
Change the layout direction of a composable by changing the LocalLayoutDirection compositionLocal.
But I have no idea how to use it in a composable to take effect.
You can use the CompositionLocalProvider to provide a custom LocalLayoutDirection.
Something like:
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl ) {
Column(Modifier.fillMaxWidth()) {
Text("Title")
Text("Subtitle")
}
}
Since I did not have your image, I tweaked your composable to:
#Composable
fun ViewToBeChanged() {
Row {
Text("Foo", modifier = Modifier.padding(end = 8.dp))
Column {
Text("Title")
Text("Subtitle")
}
}
}
That gives us:
One way to switch to RTL is to use CompositionLocalProvider and LocalLayoutDirection:
#Composable
fun RtlView() {
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) {
Row {
Text("Foo", modifier = Modifier.padding(end = 8.dp))
Column {
Text("Title")
Text("Subtitle")
}
}
}
}
Here, we are saying that we are overriding the CompositionLocal for layout direction for the contents of the trailing lambda supplied to CompositionLocalProvider(). This gives us:
This changes the layout direction used by this branch of the composable tree, for the composables itself. English is still a LTR language, so the text is unaffected.
As a generalisation of the other answers, if this is needed in different Composables we can define the following
#Composable
fun RightToLeftLayout(content: #Composable () -> Unit) {
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) {
content()
}
}
then simply use
RightToLeftLayout {
ViewToBeChanged()
}
or
RightToLeftLayout {
Row {
...
}
}
Android Jetpack Compose Colors class contains a set of color types a material themed app can be implemented with. In case my app theme requires some extra color types, how can I add these extra colors so they would be available via MaterialTheme object?
Just a small change to Valeriy Katkov's answer
In some versions of the android studio, the following code will not work
#Composable
val Colors.myExtraColor: Color
get() = if (isLight) Color.Red else Color.Green
#Composable
fun ExtraColorExample() {
Text(
text = "test",
color = MaterialTheme.colors.myExtraColor // <-- the newly added color
)
}
It will show an error
This annotation is not applicable to target 'top-level property
without backing field or delegate'
To fix this either write it like this
#get:Composable
val Colors.myExtraColor: Color
get() = if (isLight) Color.Red else Color.Green
Or
val Colors.myExtraColor: Color
#Composable
get() = if (isLight) Color.Red else Color.Green
The version I found this error in
Android Studio Arctic Fox | 2020.3.1 Canary 12
Build #AI-203.7148.57.2031.7226969, built on March 23, 2021
Runtime version: 11.0.8+10-b944.6842174 amd64
VM: OpenJDK 64-Bit Server VM by N/A
Windows 10 10.0
There are basically two approaches to this:
The naive way is to just create extension properties tot hard-code the colors. If you don't want to support multiple themes or light/dark mode this works just fine.
If you want to integrate your colors properly to the theme, you can read my article on it, as it's a bit long to inline here: https://gustav-karlsson.medium.com/extending-the-jetpack-compose-material-theme-with-more-colors-e1b849390d50
But in short, the steps are:
Create your own MyColors class that holds a reference to Colors as well as your new colors.
Create a CompositionLocal that holds a MyColor instance.
Create your theme and wrap the MaterialTheme in a CompositionLocalProvider where the CompositionLocal provides MyColors. Make sure to also assign the Colors instance from MyColors to the MaterialTheme.
Create an extension property on MaterialTheme that refers to the CompositionLocal holding MyColors. This is how you refer to your new colors.
This will allow you to introduce new colors to the theme that will update dynamically as the theme changes.
Extending Colors class
You can easily add an extension property to the Colors class so it would be available via any Colors object across your app.
#Composable
val Colors.myExtraColor: Color
get() = if (isLight) Color.Red else Color.Green
#Composable
fun ExtraColorExample() {
Text(
text = "test",
color = MaterialTheme.colors.myExtraColor // <-- the newly added color
)
}
There's an example in the compose documentation as well, see Extending Material colors.
Specifying a content alpha
In case the color you're missing differs from an existing one only by it's alpha and the purpose of the color is to change a content priority, there's no need to add an additional color to the theme. You can specify a content alpha for a hierarchy by providing a value for LocalContentAlpha.
CompositionLocalProvider(
LocalContentAlpha provides ContentAlpha.medium,
LocalContentColor provides MaterialTheme.colors.onSurface
) {
// this text is displayed using ContentAlpha.medium
// and MaterialTheme.colors.onSurface color
Text("Hello world!")
}
See Content Alpha documentation for more details. There's also Content Alpha section in Jetpack Compose Theming codelab.
For Material3, I had to extend the androidx.compose.material3.ColorScheme object, since MaterialTheme.colors does not exist.
val ColorScheme.successContainer: Color #Composable
get() = if (!isSystemInDarkTheme()) Color(0xFFd6ffe0) else Color(0xFF269300)
Text(
text = "Hello World",
modifier = Modifier.background(color = MaterialTheme.colorScheme.successContainer)
)
"CompositionLocal" answer is right, but maybe not quite easy to understand.
Android Developers on youtube send a video: "Compose by example".
https://www.youtube.com/watch?v=DDd6IOlH3io
on 6:28/22:07 Introduced this usage.
Here is my sample code to learn this part, for someone to copy:
Define the theme:
val Purple200 = Color(0xFFBB86FC)
val Purple500 = Color(0xFF6200EE)
val Purple700 = Color(0xFF3700B3)
val Teal200 = Color(0xFF03DAC5)
val yellow200 = Color(0xffffeb46)
val yellow400 = Color(0xffffc000)
val yellow500 = Color(0xffffde03)
val yellowDarkPrimary = Color(0xff242316)
val yellowLightPrimary = Color(0xffd4d3f6)
class RabbitColorPalette(
val raFirstColor: Color,
val raSecColor: Color,
val raOnFirstColor: Color,
val raOnSecColor: Color
)
val rabbitPurple = RabbitColorPalette(Purple200,Purple500,Purple700,Teal200)
val rabbitYellow = RabbitColorPalette(yellow200,yellow400,yellow500,yellowDarkPrimary)
val rabbitColors = compositionLocalOf<RabbitColorPalette>{
rabbitPurple
}
#Composable
fun RabbitThemePink(
content: #Composable() () -> Unit
) {
val colors = rabbitPurple
CompositionLocalProvider(rabbitColors provides colors){
MaterialTheme(
typography = Typography,
shapes = Shapes,
content = content
)
}
}
object RabbitTheme{
val colors: RabbitColorPalette
#Composable get() = rabbitColors.current
}
#Composable
fun RabbitThemeYellow(
content: #Composable() () -> Unit
) {
val colors = rabbitYellow
CompositionLocalProvider(rabbitColors provides colors){
MaterialTheme(
typography = Typography,
shapes = Shapes,
content = content
)
}
}
usage
class RabbitThemeActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
RabbitThemePink {
SampleLayout()
}
}
}
#Composable
fun SampleLayout() {
Column {
Text(text = "sample", modifier = Modifier.background(color = RabbitTheme.colors.raFirstColor))
Text(text = "des", modifier = Modifier.background(color = RabbitTheme.colors.raSecColor))
}
}
#Preview
#Composable
fun ConstraintLayoutContentPinkPreview() {
RabbitThemePink {
SampleLayout()
}
}
#Preview
#Composable
fun ConstraintLayoutContentYellowPreview() {
RabbitThemeYellow {
SampleLayout()
}
}
}
In my case, the theme component gets its parameters from the saved settings, i.e. The app theme is independent of the device theme. For this reason, the current answers don't work for me.
My implementation is relevant for Material 3 and directly depends on the passed parameters.
Color.kt
package com.my.app.theme
import androidx.compose.ui.graphics.Color
val SuccessLightColor = Color(0xFF436915)
val SuccessLightContainerColor = Color(0xFFC2F18D)
val SuccessDarkColor = Color(0xFFA7D474)
val SuccessDarkContainerColor = Color(0xFF2D5000)
Theme.kt
package com.my.app.theme
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
private val DarkColorScheme = darkColorScheme()
private val LightColorScheme = lightColorScheme()
var successColorSchemeColor by mutableStateOf(SuccessLightColor)
var successContainerColorSchemeColor by mutableStateOf(SuccessLightColor)
#Suppress("unused")
var ColorScheme.success: Color
get() = successColorSchemeColor
set(value) {
successColorSchemeColor = value
}
#Suppress("unused")
var ColorScheme.successContainer: Color
get() = successContainerColorSchemeColor
set(value) {
successContainerColorSchemeColor = value
}
#Composable
fun Theme(
darkTheme: Boolean = isSystemInDarkTheme(),
// Dynamic color is available on Android 12+
dynamicColor: Boolean = true,
content: #Composable () -> Unit
) {
val colorScheme = when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
}
darkTheme -> DarkColorScheme
else -> LightColorScheme
}
colorScheme.success = if (darkTheme) {
SuccessDarkColor
} else {
SuccessLightColor
}
colorScheme.successContainer = if (darkTheme) {
SuccessDarkContainerColor
} else {
SuccessLightContainerColor
}
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
content = content
)
}
Use case:
Box(
modifier = Modifier
.size(128.dp)
.background(
color = MaterialTheme.colorScheme.successContainer
)
)
Let's suppose I'm using some library that's intended to provide some UI Widgets.
Let's say this library provides a Button Widget called FancyButton.
In the other hand, I have a new project created with Android Studio 4 that allows me to create a new project with an Empty Compose Activity.
The question is:
How should I add this FancyButton to the view stack? Is it possible? Or with Jetpack Compose I can only use components that had been developed specifically for Jetpack Compose. In this case, AFAIK I could only use Android standars components (Text, MaterialTheme, etc).
If I try to use something like this:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MaterialTheme {
Greeting("Android")
FancyButton(context, "Some text")
}
}
}
then I get this error:
e: Supertypes of the following classes cannot be resolved. Please make sure you have the required dependencies in the classpath.
Currently (as of 0.1.0-dev04), there is not a good solution to this. In the future, you'll be able to simply call it as FancyButton("Some text") (no context needed).
You can see a demo of what it will look like in the Compose code here.
Update in alpha 06
It is possible to import Android View instances in a composable.
Use ContextAmbient.current as the context parameter for the View.
Column(modifier = Modifier.padding(16.dp)) {
// CustomView using Object
MyCustomView(context = ContextAmbient.current)
// If the state updates
AndroidView(viewBlock = ::CustomView, modifier = modifier) { customView ->
// Modify the custom view
}
// Using xml resource
AndroidView(resId = R.layout.view_demo)
}
You can wrap your custom view within the AndroidView composable:
#Composable
fun RegularTextView() {
AndroidView(
factory = { context ->
TextView(context).apply {
text = "RegularTextView"
textSize = 34.dp.value
}
},
)
}
And here is how to update your custom view during a recomposition, by using the update parameter:
#Composable
fun RegularTextView() {
var string by remember {
mutableStateOf("RegularTextView")
}
Column(horizontalAlignment = Alignment.CenterHorizontally) {
AndroidView(
factory = { context ->
TextView(context).apply {
textSize = 34.dp.value
}
},
update = { textView ->
textView.text = string
}
)
Spacer(modifier = Modifier.height(8.dp))
Button(
onClick = {
string = "Button clicked"
},
) {
Text(text = "Update text")
}
}
}
#Composable
fun ButtonType1(text: String, onClick: () -> Unit)
{
Button (
modifier=Modifier.fillMaxWidth().height(50.dp),
onClick = onClick,
shape = RoundedCornerShape(5.dp),
border = BorderStroke(3.dp, colorResource(id = R.color.colorPrimaryDark)),
colors = ButtonDefaults.buttonColors(contentColor = Color.White, backgroundColor = colorResource(id = R.color.colorPrimaryDark))
)
{
Text(text = text , color = colorResource(id = R.color.white),
fontFamily = montserrat,
fontWeight = FontWeight.Normal,
fontSize = 15.sp
)
}
}