首页 > 解决方案 > 我创建了一个 RecyclerView 布局,但外观与我的预期不符

问题描述

我创建了一个 RecyclerView 布局,但外观与我的预期不符

我已经检查了 layout_height list_item.xml,但是已经wrap_content。但是为什么看起来不合适。tv_title_list执行时不会出现带有 id 的 TextView

显示屏幕截图:https ://drive.google.com/open?id= 1hywe6DrXth6iwO9jIgScAxhTq1Cq3mAL 完整代码:https ://github.com/riluq/AnimeApp

list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools">
    <data>
        <variable name="topAiring" type="com.riluq.animeapp.network.TopAiring"/>
    </data>
    <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

        <com.google.android.material.card.MaterialCardView
                android:id="@+id/mcv_list"
                android:layout_width="65dp"
                android:layout_height="90dp"
                app:cardCornerRadius="5dp"
                app:cardElevation="2dp"
                app:layout_constraintTop_toTopOf="parent"
                android:layout_marginBottom="16dp" app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="8dp"
                android:layout_marginTop="16dp">
            <ImageView
                    android:id="@+id/img_list"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:scaleType="centerCrop"
                    tools:srcCompat="@android:color/holo_blue_light"
                    app:imageUrl="@{topAiring.imageUrlTopAiring}"/>
        </com.google.android.material.card.MaterialCardView>

        <TextView
                android:id="@+id/tv_title_list"
                tools:text="JoJo no Kimyou na Bouken Part 5: Ougon no Kaze"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle2"
                app:layout_constraintStart_toEndOf="@+id/mcv_list"
                android:layout_marginStart="8dp" app:layout_constraintTop_toTopOf="@+id/mcv_list"
                app:layout_constraintBottom_toBottomOf="@+id/mcv_list"
                android:layout_marginEnd="8dp" app:layout_constraintEnd_toStartOf="@+id/tv_rank_list"
                app:textTopAiringTitle="@{topAiring.titleTopAiring}"/>
        <TextView
                android:id="@+id/tv_rank_list"
                tools:text="#1"
                android:textColor="?attr/colorSecondary"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textAppearance="@style/TextAppearance.MaterialComponents.Headline5"
                app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="8dp"
                app:layout_constraintTop_toTopOf="@+id/mcv_list"
                app:textTopAiringRank="@{topAiring.rankTopAiring}"/>

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

fragment_top_airing.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools">
    <data>
        <variable
                name="viewModel"
                type="com.riluq.animeapp.topairing.TopAiringViewModel"/>
    </data>
    <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".topairing.TopAiringFragment">

        <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/rv_top_airing"
                android:layout_width="0dp"
                android:layout_height="0dp"
                android:clipToPadding="false"
                app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                app:listData="@{viewModel.topAiring}"
                tools:itemCount="16"
                tools:listitem="@layout/list_item"/>

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

TopAiringAdapter.kt

package com.riluq.animeapp.topairing

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.riluq.animeapp.databinding.ListItemBinding
import com.riluq.animeapp.network.TopAiring

class TopAiringAdapter(): ListAdapter<TopAiring, TopAiringAdapter.TopAiringViewHolder>(DiffCallback) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TopAiringViewHolder {
        return TopAiringViewHolder(ListItemBinding.inflate(LayoutInflater.from(parent.context)))
    }

    override fun onBindViewHolder(holder: TopAiringViewHolder, position: Int) {
        val topAiring = getItem(position)
        holder.bind(topAiring)
    }

    class TopAiringViewHolder(private val binding: ListItemBinding) :
        RecyclerView.ViewHolder(binding.root){

        fun bind(topAiring: TopAiring) {
            binding.topAiring = topAiring
            binding.executePendingBindings()
        }
    }
    companion object DiffCallback: DiffUtil.ItemCallback<TopAiring>() {
        override fun areItemsTheSame(oldItem: TopAiring, newItem: TopAiring): Boolean {
            return oldItem == newItem
        }

        override fun areContentsTheSame(oldItem: TopAiring, newItem: TopAiring): Boolean {
            return oldItem.idTopAiring == newItem.idTopAiring
        }

    }
}

TopAiringFragment.kt

package com.riluq.animeapp.topairing


import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProviders
import com.riluq.animeapp.databinding.FragmentTopAiringBinding


class TopAiringFragment : Fragment() {

    private val viewModel: TopAiringViewModel by lazy {
        ViewModelProviders.of(this).get(TopAiringViewModel::class.java)
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val binding = FragmentTopAiringBinding.inflate(inflater)
        binding.lifecycleOwner = this
        // Inflate the layout for this fragment
        binding.viewModel = viewModel

        binding.rvTopAiring.adapter = TopAiringAdapter()

        return binding.root
    }

}

TopAiringViewModel.kt

package com.riluq.animeapp.topairing

import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.riluq.animeapp.network.JikanMoeApi
import com.riluq.animeapp.network.TopAiring
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch

class TopAiringViewModel: ViewModel() {

    private var viewModelJob = Job()
    private val coroutineScope = CoroutineScope(viewModelJob + Dispatchers.Main)

    private val _topAiring = MutableLiveData<List<TopAiring>>()
    val topAiring: LiveData<List<TopAiring>>
        get() = _topAiring

    init {
        getTopAiring()
    }

    private fun getTopAiring() {
        coroutineScope.launch {
            val getTopAiringDeffered = JikanMoeApi.retrofitService.getTopAiringAsync()
            try {
                val listResult = getTopAiringDeffered.await().top
                if (listResult.size > 0) {
                    _topAiring.value = listResult
                }
                Log.i("TopAiringViewModel", "topAiring = ${topAiring.value?.get(0)?.titleTopAiring}")
            } catch (t: Throwable) {
                _topAiring.value = ArrayList()
                Log.i("TopAiringViewModel", t.message.toString())
            }
        }
    }

    override fun onCleared() {
        super.onCleared()
        viewModelJob.cancel()
    }
}

我期望的是这张照片的样子:https ://drive.google.com/open?id=1d1sWL0CX7gPJFvvhY13POWDAf15Hk2Pw

标签: androidxmlkotlinandroid-recyclerview

解决方案


在 recyclerview 中为左、右、上和下添加此属性:

app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
...like wise for top and bottom

推荐阅读