Отображение текста на изображении с гибкими границами

#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)
            }
        }
    }
}
 

Теперь использование этого дает мне желаемый результат:

Смотрите здесь (изображение в альбомной ориентации)