Jetpack compose TextField RTL support - textfield

XML TextField, automatically response to RTL text and align it to right.
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/textview_first"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="سلااااااممممممم"
app:layout_constraintBottom_toTopOf="#id/button_first"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
*
But, In Compose TextField, it's stick to left.
Is there any way to have TextField to align RTL text to right and LTR text to left?

Based on #Poran answer, you must add textStyle to TextField :
TextField(
value = name,
...
textStyle = TextStyle(color = Color.Black, textDirection = TextDirection.Content)
)

This is working for text view and text field->
Text->
Text(modifier = Modifier.fillMaxWidth(),
text = text,
fontSize = 20.sp,
fontFamily = FontFamily.SansSerif,
style = TextStyle(textDirection = TextDirection.Rtl)
)
TextField->
var value by remember {
mutableStateOf("")
}
TextField(value = value,
onValueChange = { value = it },
modifier = Modifier.fillMaxWidth(),
textStyle = TextStyle(textDirection = TextDirection.Rtl))

You have to add textDirection on textStyle textStyle = TextStyle(color = Color.Black, textDirection = TextDirection.ContentOrLtr)
BasicTextField(
value = text,
onValueChange = {
text = it
onSearch(it)
},
maxLines = 1,
singleLine = true,
textStyle = TextStyle(color = Color.Black, textDirection = TextDirection.ContentOrLtr),
modifier = Modifier
.fillMaxWidth()
.shadow(5.dp, CircleShape)
.background(Color.White, CircleShape)
.padding(horizontal = 20.dp, vertical = 12.dp)
.onFocusChanged {
isDisableHint = it.isFocused && text.isEmpty()
}
)
Updated my answer: I think it will solve your problem
textStyle = TextStyle(color = Color.Black, textDirection = TextDirection.ContentOrLtr)

Related

how do I pass cursor from one textfield to other textfield in jetpack compose?

I have two textfields and the user will enter their weight and target weight. When the user clicks on the target weight, a picker appears and the user chooses his weight from there. If user selects his weight and presses the OK button, I want it to automatically switch to the target weight textfield.
hear is my code
I am sharing example textfield
Column(modifier = Modifier.fillMaxWidth()) {
TextField(
value = viewModel.defaultWeightValue.value ,
modifier = Modifier
.fillMaxWidth()
.padding(5.dp),
onValueChange = { viewModel.currentWeight.value = it },
label = { Text(text = "current weight (kg)") },
shape = RoundedCornerShape(5.dp),
colors = TextFieldDefaults.textFieldColors(
textColor = Grey2,
disabledTextColor = Color.Transparent,
backgroundColor = Grey3,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent,
),
interactionSource = remember { MutableInteractionSource() }
.also { interactionSource ->
LaunchedEffect(interactionSource) {
interactionSource.interactions.collect {
if (it is PressInteraction.Press) {
// works like onClick
viewModel.isUserClickTxtField.value = true
}
}
}
}
)
TextField(
value = viewModel.targetWeight.value,
modifier = Modifier
.fillMaxWidth()
.padding(5.dp),
onValueChange = { viewModel.targetWeight.value = it },
label = { Text(text = "target weight (kg)") },
shape = RoundedCornerShape(5.dp),
colors = TextFieldDefaults.textFieldColors(
textColor = Grey2,
disabledTextColor = Color.Transparent,
backgroundColor = Grey3,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent,
focusedLabelColor = DefaultDYTColor
)
)
}
DYTLoginAndContinueButton(
text = "continue",
navController,
Screen.SignUpFourthScreen.route
)
}
if (viewModel.isUserClickTxtField.value) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Bottom
) {
Row(
modifier = Modifier
.fillMaxWidth()
.background(Color.Gray),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
InfiniteNumberPicker(
modifier = Modifier.width(60.dp),
list = viewModel.weight,
firstIndex = 0,
onSelect = {
viewModel.weightPickerState.value = it
}
)
Text(text = "kg")
InfiniteNumberPicker(
modifier = Modifier.width(60.dp),
list = viewModel.gram,
firstIndex = 0,
onSelect = {
viewModel.grPickerState.value = it
}
)
Text(text = "gram")
}
Row(
modifier = Modifier
.fillMaxWidth()
.height(IntrinsicSize.Min)
.background(Color.Gray)
.padding(start = 0.dp, top = 15.dp, end = 0.dp, bottom = 15.dp),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = "cancel",
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
color = DefaultDYTColor,
modifier = Modifier
.padding(8.dp)
.clickable {
viewModel.isUserClickTxtField.value = false
})
Divider(
color = Color.White,
modifier = Modifier
.padding(8.dp)
.fillMaxHeight() //fill the max height
.width(1.dp)
)
TextButton(onClick = {
viewModel.isUserClickTxtField.value = false
viewModel.defaultWeightValue.value = "${viewModel.weightPickerState.value} ${viewModel.grPickerState.value}"
}) {
Text(
text = "Okey",
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
color = DefaultDYTColor,
modifier = Modifier.padding(8.dp))
}
}
}
}
if user click textfield viewModel.isUserClickTxtField.value is true and picker pops up for user. if user click Okey button in picker that means user selected his weight on picker. I want to switch other textfield automatically how can I do that ?
You can use the solution provided by #bylazy or you can use the focusProperties modifier to specify the next/previous item for each TextField or composable in your screen
Then simply use the focusManager.moveFocus method to move the focus:
focusManager.moveFocus(FocusDirection.Next)
Something like:
val (item1, item2) = remember { FocusRequester.createRefs() }
val focusManager = LocalFocusManager.current
TextField(
value = text,
onValueChange = {text = it},
Modifier
.focusRequester(item1)
.focusProperties {
next = item2
right = item2
}
)
Button(
onClick = { focusManager.moveFocus(FocusDirection.Next) }
) { Text("OK") }
TextField(
value = text,
onValueChange = {text = it},
Modifier
.focusRequester(item2)
)
In your 1st TextField you can also add the keyboardActions attribute to move the focus clicking Done in the field.
TextField(
value = text,
onValueChange = {text = it},
Modifier
.focusRequester(item1)
.focusProperties {
next = item2
right = item2
},
keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(
onDone = { focusManager.moveFocus(FocusDirection.Next) }
)
)
Create and remember FocusRequester:
val focusRequester = remember { FocusRequester() }
Add this FocusRequester to the target TextField with modifier:
modifier = Modifier.focusRequester(focusRequester)
Use this code to request focus (cursor):
focusRequester.requestFocus()

how to make Parralel scroll in jetpack compose?

I am makeing a profile screen in jetpack compose
I want to make the Blue background behind the image scroll up when the image is scrolled up because it doesn't look good :)
This is what I need help with, see the gif to understand better.
how can I achieve what I want, that the blue background will scroll up also?
I tried moving the background box around the code,
out of the column at the head
out of the column at the TopBar
out of the column at the ProfileSection
but it didn't work because the column rearrange the objects so that they are ontop of each other and I just want it from behind
source code
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.politi_cal.R
#Composable
fun CelebProfileScreen() {
BlackBackgroundSquare()
Column(modifier = Modifier.fillMaxSize()) {
LazyColumn(content = {
item {
TopBar()
Spacer(modifier = Modifier.height(60.dp))
ProfileSection(
name = "Amit Segal",
company = "N12 news channel",
)
// voting bar
VotingBar(
leftyPercent = 10, rightyPercent = 90
)
// lazy column for more info
MoreInfo("Amit Segal is a journalist and a news anchor. He is the host of the N12 news channel. He is a very popular journalist. Amit Yitzchak Segal[1] (born Biz in Nisan 5, 1982, April 10, 1982) is an Israeli journalist, radio and television personality. Serves as the political commentator of the news company and a political columnist in the \"Yediot Aharonot\" newspaper. One of the most influential journalists in Israel[2]. Presents Meet the Press on Channel 12 together with Ben Caspit.")
}
})
}
}
#Composable
fun MoreInfo(information_param: String, modifier: Modifier = Modifier) {
Column(modifier = modifier.padding(start = 26.dp, end = 26.dp)) {
Text(
text = "More information",
color = Color.Black,
fontSize = 36.sp,
fontWeight = FontWeight.Bold
)
Text(
text = information_param,
color = Color.Black,
fontSize = 24.sp,
fontWeight = FontWeight.Normal,
maxLines = 10,
overflow = TextOverflow.Ellipsis
)
}
}
#Composable
fun VotingBar(
modifier: Modifier = Modifier, leftyPercent: Int, rightyPercent: Int
) {
var leftyPercentWeight: Float = (leftyPercent / 10).toFloat()
var rightyPercentWeight: Float = (rightyPercent / 10).toFloat()
val shape = RoundedCornerShape(32.dp)
Column(
Modifier.padding(start = 16.dp, end = 16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Row(
modifier = modifier
.fillMaxWidth()
.height(32.dp)
.background(Color.White)
.clip(shape)
.border(1.dp, Color.Black, shape)
) {
Column(
// add rounded corners to the left side
modifier = Modifier
.background(Color(0xFFA60321))
.weight(rightyPercentWeight)
.clip(CircleShape)
.fillMaxHeight(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
}
Column(
modifier = Modifier
.background(Color(0xFF03588C))
.fillMaxHeight(leftyPercentWeight)
.weight(1f)
.clip(CircleShape),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
// add rounded corners to the right side
) {
}
}
// second row
// stack over flow https://stackoverflow.com/questions/74619069/what-is-the-attribute-of-the-moddifier-that-i-need-to-change-to-make-the-corners?noredirect=1#comment131712293_74619069
Column(
Modifier.padding(start = 46.dp, end = 46.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Row(
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.background(Color.White),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
) {
Row {
Box(
modifier = Modifier
.size(30.dp)
.clip(CircleShape)
.background(Color(0xFFA60321))
)
Spacer(modifier = Modifier.width(10.dp))
Text(
text = "Right $rightyPercent%",
fontSize = 20.sp,
fontWeight = FontWeight.Bold
)
}
Row() {
Box(
modifier = Modifier
.size(30.dp)
.clip(CircleShape)
.background(Color(0xFF03588C))
)
Spacer(modifier = Modifier.width(10.dp))
Text(
text = "Left $leftyPercent%", fontSize = 20.sp, fontWeight = FontWeight.Bold
)
}
}
}
}
}
#Composable
fun BlackBackgroundSquare() {
Box(
// modifier fill only half the screen
modifier = Modifier
.fillMaxWidth()
.height(300.dp)
// insert background color as hex
.background(Color(0xFF2C3E50))
)
}
#Composable
fun TopBar(
modifier: Modifier = Modifier
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center,
modifier = modifier.fillMaxWidth()
) {
Text(
text = "Profile",
overflow = TextOverflow.Ellipsis,
fontWeight = FontWeight.Bold,
fontSize = 40.sp,
color = Color.White
)
}
}
#Composable
fun ProfileSection(
name: String, company: String, modifier: Modifier = Modifier
) {
Column(
modifier = modifier.fillMaxWidth(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
RoundImage(
image = painterResource(id = R.drawable.profile_pic), modifier = Modifier.size(250.dp)
)
Text(
text = name,
overflow = TextOverflow.Ellipsis,
fontWeight = FontWeight.Bold,
fontSize = 40.sp,
color = Color.Black
)
Text(
text = company,
overflow = TextOverflow.Ellipsis,
fontWeight = FontWeight.Bold,
fontSize = 20.sp,
color = Color.Black
)
}
}
#Composable
fun RoundImage(
image: Painter, modifier: Modifier = Modifier
) {
Image(
painter = image,
contentDescription = "Profile image",
modifier = modifier
.aspectRatio(1f, matchHeightConstraintsFirst = true)
.border(
width = 6.dp, color = Color.White, shape = CircleShape
)
.padding(3.dp)
.clip(CircleShape)
)
}
You do not need to use LazyColumn, if it contains only a single item, but Box is a simple component for placing components on top of each other, which could be used here for the item like this:
item {
Box {
BlackBackgroundSquare()
Column {
TopBar()
Spacer(modifier = Modifier.height(60.dp))
ProfileSection(
name = "Amit Segal",
company = "N12 news channel",
)
}
}
}
Add a state to LazyColumn, then use state.firstVisibleItemIndex to detect when first item is not visible. Use a DisposableEffect to detect index by index to prevent lag. When first idx is consumed, hide your upper bar. Could use a viewmodel to save first index. Then show action bar if first item is visible again.
DisposableEffect(key1 = listState.firstVisibleItemIndex) {
onDispose {
viewModel
.setFirstVisibleItemIdx(listState.firstVisibleItemIndex)
}
}
On enter get the index from viewmodel and scroll. If no value, just show as normal.
LaunchedEffect(viewModel.firstVisibleItemIdx) {
listState.scrollToItem(viewModel.firstVisibleItemIdx.value ?: 0)
}

How can I use textfield control for multi textfield in jetpack compose?

I have a multi text field in a screen in my android jetpack compose app and I want to check the textfields are not empty, button will be active and if one of textfield is empty, button will be active, I was asked for check box control, but I do not know how can I use it for multi text field, any idea?
#OptIn(ExperimentalComposeUiApi::class)
#Composable
fun LoginScreen(
navController: NavController,
) {
val email = remember { mutableStateOf(TextFieldValue()) }
val password = remember { mutableStateOf(TextFieldValue()) }
val passwordVisibility = remember { mutableStateOf(false) }
Column(
Modifier
.fillMaxSize()
,
horizontalAlignment = Alignment.CenterHorizontally
) {
val context = LocalContext.current
OutlinedTextField(
value = email.value,
colors = TextFieldDefaults.textFieldColors(
backgroundColor = white,
focusedIndicatorColor = Grey,
unfocusedIndicatorColor = Grey,
focusedLabelColor = Grey,
unfocusedLabelColor = Grey,
cursorColor = custom,
textColor = custom,
),
onValueChange = { email.value = it },
label = { Text(text = "Email Address") },
placeholder = { Text(text = "Email Address") },
singleLine = true,
modifier = Modifier.fillMaxWidth(0.8f)
)
Spacer(modifier = Modifier.padding(2.dp))
OutlinedTextField(
value = password.value,
colors = TextFieldDefaults.textFieldColors(
backgroundColor = white,
focusedIndicatorColor = Grey,
unfocusedIndicatorColor = Grey,
focusedLabelColor = Grey,
unfocusedLabelColor = Grey,
cursorColor = custom,
textColor = custom,
),
onValueChange = { password.value = it },
label = { Text(text = "Password") },
placeholder = { Text(text = "Password") },
singleLine = true,
modifier = Modifier.fillMaxWidth(0.8f),
trailingIcon = {
IconButton(onClick = {
passwordVisibility.value = !passwordVisibility.value
}) {
Icon(
painter = painterResource(id = R.drawable.password_eye),
contentDescription = "",
tint = if (passwordVisibility.value) custom else Grey
)
}
},
visualTransformation = if (passwordVisibility.value) VisualTransformation.None
else PasswordVisualTransformation()
)
Spacer(modifier = Modifier.padding(20.dp))
Button(
modifier = Modifier
.width(285.dp)
.height(55.dp),
onClick = {
focus.clearFocus(force = true)
model.onSignUpOne(
email.value.text,
password.value.text,
)
},
colors = ButtonDefaults.buttonColors(
backgroundColor = custom
),
shape = RoundedCornerShape(30)
) {
Text(
text = "Login",
style = TextStyle(
fontSize = 18.sp,
color = white,
)
}
}}}}
You can simply use the enabled property of the button for this.
Button(
enabled = email.value.isNotBlank() && password.value.isNotBlank()
) {
}

How to make BottomNavigationItem fill space available?

I want to make BottomNavigation with text appearing from right side of selected item. How can I make BottomNavigationItem fill available space or move other items, to prevent text from wrapping?
here's image
Tried this, but didn't work:
#Composable
fun BottomNavigationBar(
items: List<BottomNavItem>,
navController: NavController,
onItemClick: (BottomNavItem) -> Unit
) {
val backStackEntry = navController.currentBackStackEntryAsState()
BottomNavigation(
modifier = Modifier,
elevation = 0.dp,
backgroundColor = light
) {
items.forEach{
val selected = it.screen_route == backStackEntry.value?.destination?.route
BottomNavigationItem(
selected = selected,
selectedContentColor = primary_color,
unselectedContentColor = shaded,
onClick = { onItemClick(it) },
icon = {
Row(
modifier = if (selected) Modifier
.fillMaxWidth()
.padding(horizontal = 15.dp)
else Modifier
.padding(horizontal = 15.dp)
) {
Icon(
imageVector = it.icon,
contentDescription = it.title,
tint = if (selected) primary_color else shaded,
)
if (selected){
Text(
text = it.title,
color = primary_color,
textAlign = TextAlign.Center,
fontSize = 20.sp,
modifier = Modifier.padding(start = 2.dp).align(Alignment.CenterVertically),
overflow = TextOverflow.Visible
)
}
}
}
)
}
}
}
You can check solution from Jetsnack sample app. I think this is the same behavior you want to achieve.

Aligning a resized TextField in Jetpack Compose

I am having problem aligning a resized TextField in Jetpack Compose for Desktop. When I resize the width of the TextField, the TextField automatically adjust itself to center position on screen. I have tried using Modify.Align and it did not work.
Can someone help? Here is my code
#Composable
fun addSales(sales: Sales,
actionChangeSales: (sales: Sales) -> Unit,
actionQuantityInc: (() -> Unit),
actionItemNameInc: (() -> Unit)){
Column{
TextField(
value = sales.itemName,
textStyle = TextStyle(color = Color.DarkGray),
onValueChange = {
actionChangeSales(Sales(itemName = it))
actionItemNameInc.invoke()
},
label = { Text("Item name")}
)
Spacer(modifier = Modifier.height(16.dp))
OutlinedTextField(
value = roundQuantity(sales.quantitySold),
textStyle = TextStyle(color = Color.DarkGray),
onValueChange = {
actionChangeSales(Sales(quantitySold = getDoubleFromEditText(it)))
actionQuantityInc.invoke()
},
label = { Text("Quantity")},
modifier = Modifier.width(120.dp)
)
}
}
As a workaround, try to wrap OutlinedTextField with Box and apply the width modifier there:
Box(modifier = Modifier.width(120.dp)) {
OutlinedTextField(
value = "123456789",
textStyle = TextStyle(color = Color.DarkGray),
onValueChange = {},
label = { Text("Quantity") },
)
}
You have to wrap them in a Column again.
Pseudo code as below
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifiler.fillMaxWidth() // needed so it knows the full width to center the content within it
) {
// This wraps your content and centers it
Column( horizontalAlignment = Alignment.Start ){
// This wraps and aligns the content to the left/start
// place your content here
}
}