ImageView in LinearLayout in Scrollview con CardStackView e Picasso Picture non viene visualizzato

Sep 09 2020

Sto sviluppando un'applicazione Android.

Sto usando "com.yuyakaido.android:card-stack-view:2.3.4" per la libreria della pila di carte.

ImageView è in LinearLayout in ScrollView in CardView.

Quello che voglio fare è adattare l'immagine alla dimensione della carta come nell'immagine qui sotto quando la carta viene caricata all'inizio.

E se scorri verso il basso, verranno visualizzati alcuni testi come nell'immagine qui sotto

Uso Picasso per adattare l'immagine a ImageView ma l'immagine non viene visualizzata.

Questo è il frammento che ha CardStackView

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    return inflater.inflate(R.layout.fragment_card_stack, container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    initCardStackView()
}

private fun initCardStackView() {
    manager = CardStackLayoutManager(context)
    manager.setCanScrollVertical(false)
    manager.setSwipeableMethod(SwipeableMethod.Manual)
    adapter = CardStackAdapter(context, createDummyProfiles())
    cardStackView.layoutManager = manager
    cardStackView.adapter = adapter
    cardStackView.itemAnimator = DefaultItemAnimator()
}

Questo è il layout Fragment

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/linearLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    
    <com.yuyakaido.android.cardstackview.CardStackView
        android:id="@+id/cardStackView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="80dp"
        android:clipToPadding="false"/>

</LinearLayout>

Questo è il CardStackAdapter, qui ritaglio e adeguo l'immagine a ImageView con Piccaso

class CardStackAdapter(private var context: Context?, private var movies: MutableList<Movies>) :
    RecyclerView.Adapter<CardStackAdapter.ViewHolder>() {

    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        return ViewHolder(inflater.inflate(R.layout.card_view, parent, false))
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        Picasso.get().load(R.drawable.person3).fit().centerCrop().into(holder.itemView.imageView)
    }

    override fun getItemCount(): Int {
        return movies.size
    }

    fun setItems(items: MutableList<Profile>) {
        this.movies = items
    }
}

Questo è il card_view che è il layout per viewHolder di CardStackAdapter

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/cardView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="?attr/selectableItemBackground"
    android:foreground="?attr/selectableItemBackground"
    app:cardBackgroundColor="@android:color/white"
    app:cardCornerRadius="18dp"
    app:cardPreventCornerOverlap="false"
    app:cardUseCompatPadding="true">

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <ImageView
                android:id="@+id/imageView"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/lipsum"/>

        </LinearLayout>

    </ScrollView>

</androidx.cardview.widget.CardView>

Quando eseguo l'applicazione, ottengo la scheda senza l'immagine ma solo i testi come da immagine sotto

Come posso visualizzare l'immagine nella dimensione della carta quando la carta è caricata?



------------------------- AGGIORNARE ------------------------ ----

** NOTA: l'immagine verrà recuperata dal server non disegnabile in locale. Ho appena usato le immagini in drawable locale a scopo di test.

Non sono sicuro del motivo per cui l'immagine non viene visualizzata. Ma se imposto l'altezza e la larghezza di layoutParams di imageView come da codice di seguito, l'immagine viene visualizzata.

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    holder.itemView.imageView.layoutParams.height = 1918
    holder.itemView.imageView.layoutParams.width = 970
    Picasso.get().load(R.drawable.person3).fit().centerCrop().into(holder.itemView.imageView)
}

Quindi, ora la domanda è se posso impostare l'altezza e la larghezza di ImageView uguali all'altezza e alla larghezza di ScrollView( imageViewgenitore del genitore) o CardView( imageViewgenitore del genitore del genitore) NOT LinearLayout (genitore) perché l'altezza di LinearLayout dovrebbe essere "wrap_content".



------------------------- AGGIORNARE ------------------------ ----

Sembra che la tua soluzione si basi sull'altezza e la larghezza dell'immagine, ma devo adattare l'immagine in CardView o ScrollView

ecco il mio codice onBindViewHolder. Ho appena rimosso Picasso.

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    holder.itemView.imageView.setImageResource(R.drawable.person2)
}

Ecco il mio layout CardView

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/cardView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="?attr/selectableItemBackground"
    android:foreground="?attr/selectableItemBackground"
    app:cardCornerRadius="18dp"
    app:cardPreventCornerOverlap="false"
    app:cardUseCompatPadding="true">

    <androidx.core.widget.NestedScrollView
        android:fillViewport="true"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <ImageView
                android:id="@+id/imageView"
                android:src="@drawable/person2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:adjustViewBounds="true"
                android:scaleType="centerCrop"/>

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/lipsum"/>

        </LinearLayout>

    </androidx.core.widget.NestedScrollView>

</androidx.cardview.widget.CardView>

Questo è quello che ho sul mio AVD. L'immagine non riempie la parte inferiore di CardView perché si ridimensiona in base all'altezza e alla larghezza?

Risposte

1 ADM Sep 17 2020 at 19:08

Quello che ho capito dalla tua domanda aggiornato è necessario per riempire il ImageViewfino CardViewaltezza e la textViewsarà visibile dopo lo scorrimento. Questo sembra complicato ScrollViewperché in qualche modo abbiamo bisogno di impostare l'altezza dinamicamente con match_parentcui non funzionerà ScrollView.
Ho creato una soluzione qui sotto per vedere se questo allenamento fa per te. Crea una visualizzazione Immagine personalizzata e usala all'interno CardView.

class FillImageView : AppCompatImageView {
constructor(context: Context?) : super(context!!) {}
constructor(context: Context?, attrs: AttributeSet?) : super(context!!, attrs) {}
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context!!, attrs, defStyleAttr) {}

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    val parentWidth = MeasureSpec.getSize(widthMeasureSpec)
    setMeasuredDimension(parentWidth, (parent.parent as View).measuredHeight)
}
}

E aggiungi quanto NestedScrolllViewsegue all'interno di CardView

<androidx.core.widget.NestedScrollView
            android:layout_width="match_parent"
            android:fillViewport="true"
            android:layout_height="match_parent">
        <LinearLayout
                android:layout_width="match_parent"
                android:orientation="vertical"
                android:layout_height="wrap_content">
            <com.ace.myapplication.FillImageView
                    android:layout_width="match_parent"
                    android:src="@drawable/hello"
                    android:adjustViewBounds="true"
                    android:layout_height="match_parent"
                    android:scaleType="centerCrop"/>
            <TextView
                    android:layout_width="match_parent"
                    android:textSize="23sp"
                    android:padding="10dp"
                    android:layout_height="wrap_content"/>
        </LinearLayout>
    </androidx.core.widget.NestedScrollView>

PS - Potrebbe essere una brutta soluzione con l'impostazione dell'altezza, (parent.parent as View).measuredHeightma questo è tutto ciò di cui posso pensare in questo momento. amo vedere qualche soluzione elegante per questo. Non l'ho provato con CardStackView.

Aggiorna ora con RecyclerViewil problema l'elemento disegnato dopo che l'adattatore è stato impostato e dobbiamo ascoltare la layoutManagerrichiamata dell'elemento disegnato da allora. Un modo per affrontare questo problema senza renderlo complesso Impostare l' cadStackViewaltezza su imageView. Vedere il codice seguente aggiungendo solo il codice essenziale.

class CardStackAdapter(val stackViewHeight:Int, private var movies: MutableList<Moview>) :
    RecyclerView.Adapter<CardStackAdapter.ViewHolder>() {

   inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val imageView:ImageView = itemView.findViewById(R.id.imageView)
        init {
            imageView.layoutParams.height= stackViewHeight
        }
    }
}

Ora nel tuo frammento

cardStackView.post {
       initCardStackView()
   }

E cambia la creazione del dapter all'interno initCardStackViewcome segue. Inoltre non è necessario passare il contesto all'adattatore a ciascuna vista è associato un contesto. Inoltre, non utilizzare FillImageViewin questo caso utilizzare normale ImageViewnel layout xml.

// Since you are using android:padding it will be same for all sides
    val cardHeight=cardStackView.height- (2*cardStackView.paddingTop)
    val adapter = CardStackAdapter(cardHeight, createDummyProfiles())
BrunoVieira Sep 16 2020 at 02:46

Perché stai usando Picasso per caricare un disegnabile locale? Potresti semplicemente applicare la tua fonte disegnabile a ImageView.

<ImageView
    android:id="@+id/imageView"
    android:layout_width="match_parent"
    android:scaleType="fitCenter"
    android:src="@drawable/person3"
    android:layout_height="wrap_content" />

Oltre a ciò, ti consiglio vivamente di usare al NestedScrollViewposto di ScrollViewe quindi, per favore, imposta fillViewPort(Attributo di ScrollView) su true per estendere la sua altezza uguale all'altezza del bambino


Aggiornare:

Se vuoi davvero usare Picasso per caricare un URL esterno, esegui la seguente configurazione:

Picasso
    .get()
    .load([url_you_want_to_load])
    .placeholder([placeholder_you_want_to_pre_load])
    .into(imageView)

quindi, configura ImageView per adattarlo al centro e preservarne le proporzioni:

<ImageView
    android:id="@+id/imageView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:adjustViewBounds="true"
    android:scaleType="centerCrop" />