Android compose: how to position icons in the margins of a text in a row? - android-layout

I would like to have a card with the following layout:
an icon on the left;
text in the center;
an icon to the right;
The icons must always be present regardless of the length of the text:
In this regard I wrote the following code:
fun test() {
Card(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(16.dp)
) {
Row(
Modifier.fillMaxWidth().padding(all = 16.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Icon(imageVector = Icons.Default.ArrowBack, contentDescription = "Back")
Text("Title", textAlign = TextAlign.Center)
Icon(imageVector = Icons.Default.Delete, contentDescription = "Delete")
}
}
}
The problem is that if the text is too long, then the last icon "disappears":
A solution could be to use Modifier.width (x.dp) on the text, but in this case how do I set the value of x to cover the maximum possible width within the icons?

You can apply Modifier.weight(1f) to the Text composable.
Something like:
Row(
Modifier
.fillMaxWidth()
.height(30.dp)
){
Icon(imageVector = Icons.Default.ArrowBack, contentDescription = "Back")
Text("Title", textAlign = TextAlign.Center,
modifier = Modifier.weight(1f)) // Fill this with remaining space available
Icon(imageVector = Icons.Default.Delete, contentDescription = "Delete")
}

You can make this spacing arrangement with distributed weights directly.
I've added each icon weight 1 and rest of the space to title.
Or you may also use ConstraintLayout for this, but row with weights works fine too.
Row(
Modifier.fillMaxWidth().padding(16.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Icon(
modifier = Modifier.weight(1f),
imageVector = Icons.Default.ArrowBack, contentDescription = "Back"
)
Text(
modifier = Modifier.weight(8f),
text = "Title",
textAlign = TextAlign.Center
)
Icon(
modifier = Modifier.weight(1f),
imageVector = Icons.Default.Delete,
contentDescription = "Delete"
)
}

Related

Divider() doesn't work with horizontalScroll() in Jetpack Compose [duplicate]

This question already has an answer here:
Divider composable becomes invisible when placed inside composable with horizontalScroll modifier set. Is this a bug?
(1 answer)
Closed 9 months ago.
I'm trying to present a soccer table in Jetpack Compose UI. The user should be able to scroll the table both horizontally (through columns) and vertically (through rows). However, Divider() doesn't work with horizontalScroll() in Jetpack Compose and hence, the dividing line is missing in between items. If I remove horizontalScroll() from Card, it's working perfectly. How can I improve this?
Box(
modifier = Modifier
.fillMaxSize()
.background(Color(0, 0, 0, 255))
) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.horizontalScroll(rememberScrollState()),
backgroundColor = Color.White,
shape = RoundedCornerShape(topStart = 12.dp, bottomStart = 12.dp)
) {
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
) {
itemsIndexed(teams) { i, team ->
Row(
modifier = Modifier
.fillMaxWidth()
.padding(6.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = team.name,
fontSize = 18.sp,
color = Color.Black,
fontWeight = FontWeight.SemiBold,
modifier = Modifier.width(150.dp)
)
Spacer(modifier = Modifier.width(12.dp))
Text(
text = team.gamesWon.toString(),
fontSize = 18.sp,
color = Color.Black,
fontWeight = FontWeight.SemiBold,
modifier = Modifier.width(30.dp),
textAlign = TextAlign.Center
)
Spacer(modifier = Modifier.width(12.dp))
Text(
text = team.gamesLost.toString(),
fontSize = 18.sp,
color = Color.Black,
fontWeight = FontWeight.SemiBold,
modifier = Modifier.width(30.dp),
textAlign = TextAlign.Center
)
Spacer(modifier = Modifier.width(12.dp))
Text(
text = team.stadiumName,
fontSize = 18.sp,
color = Color.Black,
fontWeight = FontWeight.SemiBold,
modifier = Modifier.width(300.dp),
maxLines = 1,
textAlign = TextAlign.Center
)
}
Divider()
}
}
}
}
Since you are setting exact widths of all the things, you could just add up all the sizes and set the Divider width to match.

Jetpack Compose layout challenge

I'm trying to layout the following in compose but I cannot seem to get the alignment / arrangements to work correctly. I have tried starting with Row() and also trying starting with Column but the results are the same - misaligned.
So I have the following properties:
1. constantA = "774"
2. operator = "+"
3. constantB = "62"
4. line = "-------"
5. answer = "826"
6. icon = "checkmark"
The alignment needs to be as follows:
774
+ 52
-----
826 ✓
Any help or pointers will be appreciated!
In case you wanna use a regular Icon:
#Preview
#Composable
fun OperationPreview() {
val constantA = "774"
val operator = "+"
val constantB = "62"
val line = "-------"
val answer = "826"
Row(verticalAlignment = Alignment.Bottom) {
Column(horizontalAlignment = Alignment.End) {
Text(text = constantA)
Text(text = "$operator $constantB")
Text(text = line)
Row() {
Text(text = answer)
}
}
Icon(
modifier = Modifier
.size(10.dp)
.padding(bottom = 5.dp),
imageVector = Icons.Default.Check,
contentDescription = null
)
}
}
#Composable
fun TextAlignLayout() {
val constantA = "774" + " "
val operator = "+" + " "
val constantB = "62" + " "
val line = "-------" + " "
val answer = "826"
val icon = "✓"
Column(
modifier = Modifier
.padding(24.dp)
.fillMaxSize(),
horizontalAlignment = Alignment.End
) {
Text(constantA)
Text("$operator$constantB")
Text(line)
Text("$answer $icon")
}
}

PIXI.Text as a hole but keeping stroke

I am trying to add text to a PIXI Application as a hole, cutting through the canvas showing what's underneath it, but need to keep the stroke around each letter. I am using a blendMode to cut the text through, but it removes the stroke as well. Is it even possible?
//hacked clearing blendmode
app.renderer.state.blendModes[20] = [0,
WebGLRenderingContext.ONE_MINUS_SRC_ALPHA];
//Adding text
var style = new PIXI.TextStyle({
fontFamily: 'din-condensed',
fontSize: '400px',
fontWeight: 400,
stroke: '#25556f',
strokeThickness: 5
});
var invertedText = new PIXI.Text(text, style);
invertedText.x = 0;
invertedText.y = (height / 2) - ($(heading).height() / 2);
invertedText.blendMode = 20;
app.stage.addChild(invertedText);

What is the difference between alphabetic and ideographic in Flutter's TextBaseline enum

The TextBaseline enum in Flutter has two options:
alphabetic
ideographic
How do these values actually change the baseline?
TextBaseline.alphabetic
The alphabetic baseline is the line that the letters in alphabets like English sit on. Here is an example:
You can see that the English letters sit nicely on the line, but it cuts through the Chinese characters.
TextBaseline.ideographic
When you use the ideographic option, though, the baseline is at the bottom of the text area. Note that the Chinese characters don't actually sit right on the line. Rather, the line is at the very bottom of the text line.
Supplemental code
You can plug this into a CustomPaint widget (as described here) to reproduce the above examples.
#override
void paint(Canvas canvas, Size size) {
final textStyle = TextStyle(
color: Colors.black,
fontSize: 30,
);
final textSpan = TextSpan(
text: 'My text 文字',
style: textStyle,
);
final textPainter = TextPainter(
text: textSpan,
textDirection: TextDirection.ltr,
);
textPainter.layout(
minWidth: 0,
maxWidth: size.width,
);
print('width: ${textPainter.width}');
print('height: ${textPainter.height}');
// draw a rectangle around the text
final left = 0.0;
final top = 0.0;
final right = textPainter.width;
final bottom = textPainter.height;
final rect = Rect.fromLTRB(left, top, right, bottom);
final paint = Paint()
..color = Colors.red
..style = PaintingStyle.stroke
..strokeWidth = 1;
canvas.drawRect(rect, paint);
// draw the baseline
final distanceToBaseline =
textPainter.computeDistanceToActualBaseline(TextBaseline.ideographic);
print('distanceToBaseline: ${distanceToBaseline}');
canvas.drawLine(
Offset(0, distanceToBaseline),
Offset(textPainter.width, distanceToBaseline),
paint,
);
// draw the text
final offset = Offset(0, 0);
textPainter.paint(canvas, offset);
}

Remove tint color but keep font color UISegmentedControl

I would like to remove the selected color from my UISegmetedControl. I know tintColor can do this but that also removes the font color with it. Also using kCTForegroundColorAttributeName will remove both.
Side note I made a UIView and placed it above the selected segment to show selected state. I thought this would look better. Trying to branch out and make my own custom controls.
public let topLine = UIView()
override func awakeFromNib() {
super.awakeFromNib()
self.removeBorders()
setFont()
addTopLine()
}
func setFont() {
let font = UIFont(name: FontTypes.avenirNextUltraLight, size: 22.0)!
let textColor = UIColor.MyColors.flatWhite
let attribute = [kCTFontAttributeName:font]
self.setTitleTextAttributes(attribute, for: .normal)
}
func addTopLine() {
topLine.backgroundColor = UIColor.MyColors.flatWhite
let frame = CGRect(x: 7,
y: -5,
width: Int(self.frame.size.width)/2,
height: 2)
topLine.frame = frame
self.addSubview(topLine)
}
struct FontTypes {
static let avenirNextRegular = "AvenirNext-Regular"
static let avenirLight = "Avenir-Light"
static let avenirNextUltraLight = "AvenirNext-UltraLight"
}
TintColor is attach with
Background colour of Selected segment,
Text color of Unselected segment and
Border colour of UISegmentedControl.
So, if you going to change tintColor to white, then background colour and tint color Both are gone.
You need to set Selected/Unselected text attribute like below:
mySegment.tintColor = .white
let selectedAtrribute = [NSAttributedStringKey.foregroundColor: UIColor.red, NSAttributedStringKey.font: UIFont.systemFont(ofSize: 16)]
mySegment.setTitleTextAttributes(selectedAtrribute as [NSObject : AnyObject], for: UIControlState.selected)
let unselected = [NSAttributedStringKey.foregroundColor: UIColor.black, NSAttributedStringKey.font: UIFont.systemFont(ofSize: 16)]
mySegment.setTitleTextAttributes(unselected as [NSObject : AnyObject], for: UIControlState.normal)

Resources