#android #xml #kotlin #layout #android-constraintlayout
#Android #xml #kotlin #макет #android-constraintlayout
Вопрос:
я использую glide v4 для загрузки изображения с URL-адреса в ImageView
. Вот так:
GlideApp.with(view.context)
.load(url)
.into(view)
Изображение находится внутри a ViewPager2
. Так что мой ConstraintLayout
должен иметь match_parent
как ширину, так и высоту. Это мой макет:
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@ id/image_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:adjustViewBounds="true"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Изображения могут быть разных размеров. Некоторые из них выше, чем в ширину, а некоторые шире, чем в высоту. При match_parent
включенном представлении он всегда заполняет как можно больше места. Это то, чего я хочу. Но границы изображения всегда будут заполнять весь экран. Теперь мне нужно добавить текстовое наложение в нижней части этого изображения, не превышая фактическое изображение внутри ImageView
. Я попытался добавить следующее TextView
и использовать ограничения:
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@id/image_view"
app:layout_constraintEnd_toEndOf="@id/image_view"
app:layout_constraintBottom_toBottomOf="@id/image_view"
android:text="Some text overlay"
android:textAlignment="center"
android:textColor="#FFFFFF"
android:background="#000000" />
Потому что мои ImageView
границы match_parent
TextView
— это черный фон, растянутый по всему экрану. Установка ImageView
‘s width и height на wrap_content
(даже с adjustViewBounds="true"
) всегда приводит к нулевой ширине и высоте, поскольку изображение загружается во время выполнения первого макета.
Как я могу показать лениво загруженное изображение, занимающее как можно больше места, с правильными границами вида (в портретной и альбомной ориентации), чтобы я мог правильно использовать ограничения макета на других видах, не зная заранее никакого соотношения сторон, ширины или высоты? Альтернатива: как решить мою конкретную проблему с другим макетом / ViewGroup
?
Комментарии:
1. Я не совсем понимаю ваш вопрос
2. Не рекомендуется использовать
match_parent
для прямых дочерних элементов ConstraintLayout. Попробуйте использовать0dp
(для соответствия ограничениям) для обоих измерений в ImageView и посмотрите, поможет ли это вам решить проблему.3. Использование 0dp для обоих результатов в одном и том же макете. Текстовый вид по-прежнему слишком широк
Ответ №1:
Я думаю, что могу помочь, но я не до конца понимаю вопрос. Вот вам совет. если вы хотите, чтобы изображение заполняло весь родительский элемент, затем установите ограничения так, чтобы они соответствовали родительскому элементу без заполнения (при условии, что вы используете Constraintlayout, который вы должны использовать). И поскольку вы не уверены в соотношении сторон изображений, вам нужно либо использовать атрибут scaleType fitXY, либо centerCrop, чтобы изображение заполняло весь родительский элемент. fitXY может исказить изображение, поэтому я обычно использую centerCrop.
Комментарии:
1. Привет, мне нужно показать полное изображение без искажений. Так что fitCenter — это то, что мне нужно. Проблема заключается в наложении текста. Смотрите мое связанное изображение. Текстовый блок не должен быть шире фактического изображения
Ответ №2:
Я немного отредактировал этот пользовательский ImageView
код (https://github.com/maurycyw/StaggeredGridViewDemo/blob/master/src/com/example/staggeredgridviewdemo/views/ScaleImageView.java):
package de.xxx.xxx.controls
import android.content.Context
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.util.AttributeSet
import android.widget.RelativeLayout
import androidx.appcompat.widget.AppCompatImageView
/**
*
* This view will auto determine the width or height by determining if the
* height or width is set and scale the other dimension depending on the images dimension
*
* This view also contains an ImageChangeListener which calls changed(boolean isEmpty) once a
* change has been made to the ImageView
*
* @author Maurycy Wojtowicz
*/
class ScaleImageView : AppCompatImageView {
var imageChangeListener: ImageChangeListener? = null
private var scaleToWidth =
false // this flag determines if should measure height manually dependent of width
constructor(context: Context) : super(context) {
init()
}
constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(
context,
attrs,
defStyle
) {
init()
}
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
init()
}
private fun init() {
this.scaleType = ScaleType.CENTER_INSIDE
}
override fun setImageBitmap(bm: Bitmap?) {
super.setImageBitmap(bm)
if (imageChangeListener != null) imageChangeListener!!.changed(bm == null)
}
override fun setImageDrawable(d: Drawable?) {
super.setImageDrawable(d)
if (imageChangeListener != null) imageChangeListener!!.changed(d == null)
}
override fun setImageResource(id: Int) {
super.setImageResource(id)
}
interface ImageChangeListener {
// a callback for when a change has been made to this imageView
fun changed(isEmpty: Boolean)
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val widthMode = MeasureSpec.getMode(widthMeasureSpec)
val heightMode = MeasureSpec.getMode(heightMeasureSpec)
var width = MeasureSpec.getSize(widthMeasureSpec)
var height = MeasureSpec.getSize(heightMeasureSpec)
/**
* if both width and height are set scale width first. modify in future if necessary
*/
scaleToWidth = if (widthMode == MeasureSpec.EXACTLY || widthMode == MeasureSpec.AT_MOST) {
true
} else if (heightMode == MeasureSpec.EXACTLY || heightMode == MeasureSpec.AT_MOST) {
false
} else throw IllegalStateException("width or height needs to be set to match_parent or a specific dimension")
if (drawable == null || drawable.intrinsicWidth == 0) {
// nothing to measure
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
return
} else {
if (scaleToWidth) {
val iw = this.drawable.intrinsicWidth
val ih = this.drawable.intrinsicHeight
var heightC = width * ih / iw
if (height > 0) if (heightC > height) {
// dont let hegiht be greater then set max
heightC = height
width = heightC * iw / ih
}
this.scaleType = ScaleType.FIT_CENTER
setMeasuredDimension(width, heightC)
} else {
// need to scale to height instead
var marg = 0
if (parent != null) {
if (parent.parent != null) {
marg = (parent.parent as RelativeLayout).paddingTop
marg = (parent.parent as RelativeLayout).paddingBottom
}
}
val iw = this.drawable.intrinsicWidth
val ih = this.drawable.intrinsicHeight
width = height * iw / ih
height -= marg
setMeasuredDimension(width, height)
}
}
}
}
Теперь использование этого дает мне желаемый результат: