Reputation: 466
I have an app with a horizontal recyclerview that displays a square image with an overlaid handle and button in the bottom corners of the image (controlled with a constraint layout).
As the images displayed are all svg graphics, I'd like each of these images to expand to fill the available vertical space. However on some large screens, I'm finding there is enough space that the images then get blown up to an overly large size and so only one or two are displayed on the screen.
What I would like is for each image in the recycler view to scale to fill the space up to a maximum size of, say, 120dp. I have tried to achieve this with a custom image view that overrides onMeasure:
class ComponentImageView : AppCompatImageView {
constructor(context: Context?) : super(context) {}
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
var size = 0
val width = measuredWidth
val height = measuredHeight
val heightWithoutPadding = height - paddingTop - paddingBottom
// set the dimensions
size = heightWithoutPadding
var dp = (size / resources.displayMetrics.density + 0.5f)
if(dp > 120) {dp = 120f}
val px : Int = (dp * resources.displayMetrics.density + 0.5f).toInt()
setMeasuredDimension(px + paddingLeft + paddingRight, px + paddingTop + paddingBottom)
}
}
And have used it in the xml like this:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content" android:layout_height="match_parent">
<bw.graph.ComponentImageView
android:id="@+id/component_block_image"
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<bw.smith.TouchableImageView
android:id="@+id/component_block_handle"
style="@style/ComponentListIcon"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="@id/component_block_image"
app:srcCompat="@drawable/ic_drag_handle_gray_24dp" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/component_block_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/component_block_edit"
style="@style/ComponentListIcon"
app:layout_constraintStart_toStartOf="@id/component_block_image"
app:layout_constraintBottom_toBottomOf="@id/component_block_image"
app:srcCompat="@drawable/ic_edit_gray_24dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
While the image ends up being the correct width, the view itself still fills all the vertical height. So the result is that the image is centered in the available vertical height, and the handle and button that are intended to be overlaid appear to be floating away from the image.
Is there a way to achieve what I want? If I just manually set the android:layout_height attribute to the desired dp (e.g. between 48dp and 120dp) it looks good, I'd just like to find a way to set this in xml or programmatically so that it looks good on different screens without me having to worry.
Upvotes: 2
Views: 530
Reputation: 54204
ConstraintLayout
supports this out of the box, via the app:layout_constraintHeight_max
attribute. Add these to the view you want to have stretch:
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHeight_max="[your value here]"
Note that when the parent is taller than the max value given, the view will be centered (vertically) within the parent, unless you add bias:
app:layout_constraintVertical_bias="[0 - 1]"
A bias value of 0
will fix the view to the top of the screen, while 1
will fix it to the bottom. You can use any fractional value if you want to tweak the positioning (e.g., 0.33
to have it be one third from the top of the screen).
In cases where the view is not limited by the max, this bias value will have no effect.
Upvotes: 2