[英]Recycler view does not show
我有一個帶有網格布局的回收站視圖,它顯示帶有圖像、標題、描述和價格的卡片,但它沒有顯示任何內容。 數據已正確獲取,我假設布局文件中一定有錯誤,但我不知道它是什么。
這是片段代碼
package io.keepcoding.androidfinalproject.ui.products
import android.app.SearchManager
import android.content.Context
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.*
import android.widget.SearchView
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import io.keepcoding.androidfinalproject.R
import io.keepcoding.androidfinalproject.domain.Product
import io.keepcoding.androidfinalproject.repository.DataManager
import io.keepcoding.androidfinalproject.utils.CustomViewModelFactory
import io.keepcoding.androidfinalproject.utils.Status
import android.Manifest
import android.util.Log
import android.widget.Toast
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.GridLayoutManager
import io.keepcoding.androidfinalproject.ui.main.ClientActivity
import kotlinx.android.synthetic.main.fragment_products.*
/**
* A simple [Fragment] subclass.
* Use the [Products.newInstance] factory method to
* create an instance of this fragment.
*/
class ProductsFragment : Fragment() {
private val viewModel: ProductsFragmentViewModel by lazy {
val factory = CustomViewModelFactory(requireActivity().application,
DataManager())
ViewModelProvider(this, factory).get(ProductsFragmentViewModel::class.java)
}
private val LOCATION_PERMISSION_REQUEST_CODE = 2000
private var latitude: Double = 51.507351
private var longitude: Double = -0.127759
private var selectedRadius : Int = 1000
private var productViewModels: List<Product>? = null
private var productsAdapter: ProductsAdapter? = null
var productsInteractionListener: ProductInteractionListener? = null
override fun onAttach(context: Context) {
super.onAttach(context)
if (context is ProductInteractionListener){
productsInteractionListener = context
} else
throw IllegalArgumentException("Context does not implement product interaction listener")
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_products, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
this.setUpRecyclerView()
this.prepRequestLocationUpdates()
this.fetchData()
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.products_search, menu)
activity?.let { activity ->
val searchViewItem = menu.findItem(R.id.action_search)
val searchManager = activity.getSystemService(Context.SEARCH_SERVICE) as SearchManager
val searchView = searchViewItem.actionView as SearchView
searchView.queryHint = "Search products"
searchView.setSearchableInfo(searchManager.getSearchableInfo(activity.componentName))
searchView.isIconifiedByDefault = false
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(p0: String?): Boolean {
return false
}
override fun onQueryTextChange(newText: String?): Boolean {
var text = newText?.toLowerCase()
text?.let {
viewModel.searchProducts(selectedRadius, latitude, longitude, it)
}
return true
}
})
}
super.onCreateOptionsMenu(menu, inflater)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
selectedRadius = when(item.itemId) {
R.id.one_radius -> 1000
R.id.two_radius -> 2000
R.id.three_radius -> 3000
R.id.four_radius -> 4000
else -> {
5000
}
}
return super.onOptionsItemSelected(item)
}
private fun setUpAdapter() {
context?.let { context ->
productsAdapter = ProductsAdapter(context) {
this.productsInteractionListener?.goToProductDetail()
}
productViewModels?.let { products ->
productsAdapter?.setData(products)
}
}
}
private fun setUpRecyclerView(){
productsList.layoutManager = GridLayoutManager(context, 3)
productsList.addItemDecoration(DividerItemDecoration(context, GridLayoutManager.VERTICAL))
}
private fun setUpObservers() {
viewModel.getProducts().observe(viewLifecycleOwner, Observer { products ->
when(products.status){
Status.SUCCESS -> {
productViewModels = products.data
Log. d("PRODUCTS", productViewModels.toString())
this.setUpAdapter()
productsList.visibility = View.VISIBLE
loadingView.visibility = View.INVISIBLE
retry.visibility = View.INVISIBLE
}
Status.LOADING -> {
productsList.visibility = View.INVISIBLE
loadingView.visibility = View.VISIBLE
retry.visibility = View.INVISIBLE
}
Status.ERROR -> {
productsList.visibility = View.INVISIBLE
loadingView.visibility = View.INVISIBLE
retry.visibility = View.VISIBLE
}
}
})
}
private fun setUpListeners(){
TODO("Set up retry button listener")
}
private fun fetchData() {
viewModel.fetchProducts(selectedRadius, latitude, longitude)
this.setUpObservers()
}
private fun prepRequestLocationUpdates() {
if (ContextCompat.checkSelfPermission(requireActivity().application, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
requestLocationUpdates()
} else {
val permissionRequest = arrayOf(Manifest.permission.ACCESS_FINE_LOCATION)
requestPermissions(permissionRequest, LOCATION_PERMISSION_REQUEST_CODE)
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
when(requestCode){
LOCATION_PERMISSION_REQUEST_CODE -> {
if(grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED){
requestLocationUpdates()
} else {
Toast.makeText(requireActivity().application, "Unable to update location without permission", Toast.LENGTH_LONG).show()
}
} else -> {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
private fun requestLocationUpdates(){
viewModel.getLocationData().observe(viewLifecycleOwner, Observer { location ->
latitude = location.latitude
longitude = location.longitude
})
}
companion object {
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @return A new instance of fragment Products.
*/
@JvmStatic
fun newInstance() =
ProductsFragment()
}
}
和適配器
package io.keepcoding.androidfinalproject.ui.products
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
import io.keepcoding.androidfinalproject.R
import io.keepcoding.androidfinalproject.domain.Product
import kotlinx.android.synthetic.main.product_item.view.*
class ProductsAdapter(val context: Context, val productClickListener: ((Product) -> Unit)? = null) : RecyclerView.Adapter<ProductsAdapter.ProductHolder>(){
private var productItems : List<Product> = listOf<Product>()
private var productsInteractionListener: ((View) -> Unit)? = {
if(it.tag is Product){
productClickListener?.invoke(it.tag as Product)
} else {
throw IllegalArgumentException("Product item view's tag is not set to a Product object")
}
}
fun setData(productItems: List<Product>){
this.productItems = productItems
notifyDataSetChanged()
}
inner class ProductHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
var product: Product? = null
set(value) {
field = value
itemView.tag = field
field?.let {
Glide.with(context)
.load(it.photos?.get(0))
.apply {
RequestOptions()
.placeholder(R.drawable.ic_launcher_background)
}.into(itemView.productImage)
itemView.productTitle.text = it.name
itemView.productDesc.text = it.description
itemView.productPrice.text = (it.price?.toDouble()?.div(100)).toString()
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductHolder {
val view = LayoutInflater.from(context).inflate(R.layout.product_item, parent, false)
return ProductHolder(view) }
override fun getItemCount(): Int {
return this.productItems.size
}
override fun onBindViewHolder(holder: ProductHolder, position: Int) {
val product = productItems.get(position)
holder.product = product
holder.itemView.setOnClickListener(productsInteractionListener)
}
}
和布局文件
片段布局
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
tools:context=".ui.products.ProductsFragment"
android:layout_height="match_parent"
android:layout_width="wrap_content"
>
<include
android:id="@+id/loadingView"
layout="@layout/view_loading"
/>
<include
android:id="@+id/retry"
layout="@layout/view_retry"
android:visibility="invisible"
/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/productsList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible"
/>
</FrameLayout>
項目布局
<?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="400dp"
>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<ImageView
android:id="@+id/productImage"
android:layout_width="match_parent"
android:layout_height="250dp"
/>
<TextView
android:id="@+id/productTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="1"
/>
<TextView
android:id="@+id/productDesc"
android:layout_width="match_parent"
android:layout_height ="wrap_content"
android:maxLines="4"
/>
<TextView
android:id="@+id/productPrice"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="1"
android:layout_gravity="bottom|end"
/>
</LinearLayout>
</androidx.cardview.widget.CardView>
</GridLayout>
以及片段布局文件中包含的布局之一
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:gravity="center"
android:layout_height="wrap_content">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/loading"
android:textSize="20sp"
/>
</LinearLayout>
錯過這條線
productsList.adapter = productsAdapter
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.