Swift - auto layout UILabel height based on its contents - swift

I am having trouble setting up auto layout for UILabel and would like to get help on this.
In the picture, I have created yellow and green UILabels.
What I want to achieve is dynamically adjust the yellow UILabel height based on its content's number of lines, and anchor top of green box to anchor bottom of yellow box.
Currently, I have code as follow:
// Yellow UILabel
addSubview(captionLabel)
captionLabel.anchor(top: actionButtonsStackView.bottomAnchor, left: leadingAnchor, bottom: nil, right: trailingAnchor, paddingTop: 0, paddingLeft: 8, paddingBottom: 0, paddingRight: 8, width: 0, height: 0)
captionLabel.heightAnchor.constraint(greaterThanOrEqualToConstant: 0).isActive = true
// Green UILabel
addSubview(dateLabel)
dateLabel.anchor(top: captionLabel.bottomAnchor, left: leadingAnchor, bottom: bottomAnchor, right: trailingAnchor, paddingTop: 0, paddingLeft: 8, paddingBottom: 0, paddingRight: 8, width: 0, height: 0)
Note: the anchor function sets top, leading, bottom, and trailing
constraints with respective paddings.
As you can see, the yellow UILabel takes up more space than it actually needs.
If I leave top constraint from green UILabel, the yellow box actually starts to work as I expect:
And the code for this looks like:
// Yellow UILabel
addSubview(captionLabel)
captionLabel.anchor(top: actionButtonsStackView.bottomAnchor, left: leadingAnchor, bottom: nil, right: trailingAnchor, paddingTop: 0, paddingLeft: 8, paddingBottom: 0, paddingRight: 8, width: 0, height: 0)
captionLabel.heightAnchor.constraint(greaterThanOrEqualToConstant: 0).isActive = true
// Green UILabel
addSubview(dateLabel)
dateLabel.anchor(top: nil, left: leadingAnchor, bottom: bottomAnchor, right: trailingAnchor, paddingTop: 0, paddingLeft: 8, paddingBottom: 0, paddingRight: 8, width: 0, height: 0)
What am I doing wrong here?
Actually, removing bottomAnchor from green box make it work:
And the code for this looks like:
// Yellow UILabel
addSubview(captionLabel)
captionLabel.anchor(top: actionButtonsStackView.bottomAnchor, left: leadingAnchor, bottom: nil, right: trailingAnchor, paddingTop: 0, paddingLeft: 8, paddingBottom: 0, paddingRight: 8, width: 0, height: 0)
captionLabel.heightAnchor.constraint(greaterThanOrEqualToConstant: 0).isActive = true
// Green UILabel
addSubview(dateLabel)
dateLabel.anchor(top: captionLabel.bottomAnchor, left: leadingAnchor, bottom: nil, right: trailingAnchor, paddingTop: 0, paddingLeft: 8, paddingBottom: 0, paddingRight: 8, width: 0, height: 0)
But why is it working? I thought by setting greaterThenOrEqual constant, the yellow UILabel auto size itself to just enough size to contain its contents, and the green UILabel adjust its size accordingly to bottomAnchor's yellow UILabel.

That because you're adding two labels which have same priority of vertical content hugging (low by default). If you want the the green label get higher, you can set the Content Hugging Priority value of the red one to high or required. Here the code:
// Yellow UILabel
addSubview(captionLabel)
captionLabel.setContentHuggingPriority(.defaultHigh, for: .vertical)
captionLabel.anchor(top: actionButtonsStackView.bottomAnchor, left: leadingAnchor, bottom: nil, right: trailingAnchor, paddingTop: 0, paddingLeft: 8, paddingBottom: 0, paddingRight: 8, width: 0, height: 0)
// Green UILabel
addSubview(dateLabel)
dateLabel.anchor(top: captionLabel.bottomAnchor, left: leadingAnchor, bottom: bottomAnchor, right: trailingAnchor, paddingTop: 0, paddingLeft: 8, paddingBottom: 0, paddingRight: 8, width: 0, height: 0)
For more details you can this article: https://medium.com/#abhimuralidharan/ios-content-hugging-and-content-compression-resistance-priorities-476fb5828ef

Related

pseudo selector after not working when nested in wild card class selector

I'm trying to make a custom TextField using MUI v4. After discovering that we cannot use [class selectors when using nested themes][1], we are trying to switch to class wildcard selectors they recommend in the answer. It seems like the pseudo selector after is no longer working when nested under a class wildcard selector.
.root {
'& [class*="MuiInputBase-root"]': {
height: '56px',
'&::after': {
content: '""',
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
borderStyle: 'solid',
borderColor: '#000000',
borderWidth: '1px',
borderRadius: '8px',
},
},
},
Even though it is working when not nested
.root {
'& [class*="MuiInputBase-root"]::after': {
content: '""',
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
borderStyle: 'solid',
borderColor: '#000000',
borderWidth: '1px',
borderRadius: '8px',
},
},
I'm passing in the classes by spreading
const styles = useStyles();
<MuiTextField classes={...classes} />
Am I doing anything wrong?
[1]: How reliable are MUI Global Class names in JSS?

How to make a fill an image with white whilst keeping transparent pixels in flutter

I played around with the ColorFilter.matrix, greying the child. But what I want is a pure white replacement for any non transparent pixel.
Any idea?
final greyedMatrix = ColorFilter.matrix(<double>[
0.2126, 0.7152, 0.0722, 0, 0,
0.2126, 0.7152, 0.0722, 0, 0,
0.2126, 0.7152, 0.0722, 0, 0,
0, 0, 0, 1, 0,
]);
Widget white(BuildContext context) {
return ColorFiltered(
colorFilter: greyedMatrix,
child:
Text(icon,
style: Theme.of(context)
.textTheme
.headline1!
.apply(fontSizeFactor: 2.3)),
);

Carousel slider with lines instead of dots flutter

I would like to make a Carousel slider in flutter with lines (look at the image), but always finding with dots.
Thanks in advance
Carousel slider with lines
I found a solution with dots_indicator https://pub.dev/packages/dots_indicator
DotsIndicator(
dotsCount: length ?? 0,
position: currentIndexPage.toDouble(),
decorator: DotsDecorator(
spacing: EdgeInsets.only(left: 3, right: 3),
shape: Border(),
activeShape: Border(),
size: Size(
(width - 50) / length, 5),
activeSize: Size(
(width - 50) / length, 5),
color: Colores().blanco(opacity: 0.4),
activeColor: Colores().blanco()),
)

Swift animating view height

I am trying to chain 2 animations. But can not get the second animation (change of height) working.
1st try:
self.customView.frame = CGRect(x: 20, y: 0, width: width, height: 76)
UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 1, options: .curveEaseInOut, animations: {
self.customView.frame = CGRect(x: 20, y: 20, width: 280, height: 76)
}, completion: { (finished: Bool) in
UIView.animate(withDuration: 0.3) {
self.customView.frame = CGRect(x: 20, y: 20, width: 280, height: 136)
}
})
2nd one:
self.customView.frame = CGRect(x: 20, y: 0, width: width, height: 76)
UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 1, options: .curveEaseInOut, animations: {
self.customView.frame = CGRect(x: 20, y: 20, width: 280, height: 76)
}, completion: { (finished: Bool) in
UIView.animate(withDuration: 0.3) {
var heightConstraint = self.customView.heightAnchor.constraint(equalToConstant: 136)
heightConstraint.isActive = true
self.view.layoutIfNeeded()
}
})

Chart area width and height vs.chart options width and height

I'm just getting some experience with Google Charts and I'm having a hard time understanding the difference between setting a width and height in the chart options vs. setting the width and height in the chart area settings. For example, I've seen this done:
var options = {
width: '500px',
height: '400px',
chartArea: {
left: "15%",
top: "5%",
height: "80%",
width: "75%"
},
//chartArea: { top: 10, left: 80, bottom: 50 },
legend: { position: 'bottom', alignment: 'start' },
annotations: { alwaysOutside: true},
hAxis: {
gridlines: { count: 10 },
},
If I had to guess, this is telling Google Charts to use a 'canvas' size of 500 x 400 pixels but the chart itself should only consume 75% of the width of that and 80% of the height. Is this correct?
chart options height & width are for the entire chart in respect to the chart's container,
including axis labels, titles, legends, etc...
option chartArea is for the inside portion of the chart,
where the plot actually occurs, excluding any labels on the edges...
the following options will stretch the chart to the full width and height of the chart's container,
and stretch the chart area to the full width and height of the chart,
leaving room on the edges for the labels (top, left, bottom, right)
chartArea: {
height: '100%',
width: '100%',
top: 32,
left: 32,
bottom: 32,
right: 16
},
height: '100%',
width: '100%',
see following working snippet...
google.charts.load('current', {
packages: ['controls', 'corechart']
}).then(function () {
var chart = new google.visualization.ChartWrapper({
chartType: 'ScatterChart',
containerId: 'chart',
dataTable: google.visualization.arrayToDataTable([
['x', 'y'],
[10, 15],
[15, 13],
[18, 20],
[24, 26],
[34, 30],
[40, 43],
[49, 48],
[50, 55],
[65, 67],
[70, 70],
[72, 70],
[73, 70],
[80, 85]
]),
options: {
chartArea: {
height: '100%',
width: '100%',
top: 32,
left: 32,
bottom: 32,
right: 16
},
height: '100%',
width: '100%',
legend: {
position: 'top'
}
}
});
chart.draw();
window.addEventListener('resize', function () {
chart.draw();
}, false);
});
html, body {
height: 100%;
margin: 0px 0px 0px 0px;
overflow: hidden;
padding: 0px 0px 0px 0px;
}
.chart {
height: 100%;
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div class="chart" id="chart"></div>