【问题标题】:OnClick not working properly within recycler adaptor in fragmentOnClick 在片段的回收器适配器中无法正常工作
【发布时间】:2021-10-01 15:45:43
【问题描述】:

你好 stackoverflow 社区, 我正在片段内的回收器适配器上工作,我在其上创建了一个点击监听器接口,我在片段中有一个回调。我面临的问题是它有时会工作,但大多数时候它不会产生回调。让我知道我在这做错了什么..

是不是我的视图没有获得点击监听器,因为我添加了视图上未显示的涟漪效果?

或者我需要将监听器放在活动中而不是片段中,我这样做了但没有结果。

我的adatper类的代码

class UserMoneyRequestsAdaptor(
postItems: ArrayList<UserMoneyRequest>?, recItemClick: RecItemClick
) : RecyclerView.Adapter<BaseViewHolder>() {

private var isLoaderVisible = false
var mPostItems: ArrayList<UserMoneyRequest>? = postItems
var recItemClick: RecItemClick? = null

init {
    this.recItemClick = recItemClick
}

interface RecItemClick {
    fun onAcceptReqest(position: Int, moneyRequestModel: UserMoneyRequest)
    fun onCancelReqest(position: Int, moneyRequestModel: UserMoneyRequest)
}

companion object {
    private const val VIEW_TYPE_LOADING = 0
    private const val VIEW_TYPE_NORMAL = 1
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
    return when (viewType) {
        VIEW_TYPE_NORMAL -> ViewHolder(
            LayoutInflater.from(parent.context)
                .inflate(R.layout.user_request_list_item, parent, false)
        )
        VIEW_TYPE_LOADING -> ProgressHolder(
            LayoutInflater.from(parent.context).inflate(R.layout.item_loading, parent, false)
        )
        else -> ViewHolder(
            LayoutInflater.from(parent.context)
                .inflate(R.layout.user_request_list_item, parent, false)
        )
    }
}

override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
    holder.onBind(position)
    holder.setIsRecyclable(false)
}

override fun getItemViewType(position: Int): Int {
    return if (isLoaderVisible) {
        if (position == mPostItems!!.size - 1) VIEW_TYPE_LOADING else VIEW_TYPE_NORMAL
    } else {
        VIEW_TYPE_NORMAL
    }
}

override fun getItemCount(): Int {
    return if (mPostItems == null) 0 else mPostItems!!.size
}

fun addItems(postItems: ArrayList<UserMoneyRequest>) {
    mPostItems!!.addAll(postItems!!)
    notifyDataSetChanged()
}

fun addLoading() {
    isLoaderVisible = true

    mPostItems!!.add(
        UserMoneyRequest(
            "-1", "", "", "", "", "", "", "", "", "", "", UserAccount(
                "",
                "",
                "",
                "",
                Currency("", "", ""),
                User("", "")
            )
        )
    )
    notifyItemInserted(mPostItems!!.size - 1)
}

fun addData(listItems: ArrayList<UserMoneyRequest>) {
    val size = mPostItems!!.size
    mPostItems!!.addAll(listItems)
    val sizeNew = this.mPostItems!!.size
    notifyItemRangeChanged(size, sizeNew)
}

fun addAll(list: java.util.ArrayList<UserMoneyRequest>) {
    mPostItems!!.addAll(list)
    notifyDataSetChanged()
}

fun updateItem(pos: Int, paymentLinkListModel: UserMoneyRequest) {
    notifyItemChanged(pos)
}

fun addOneItem(postItem: UserMoneyRequest) {
    mPostItems!!.add(0, postItem)
    notifyDataSetChanged()
}

fun removeOneItem(position: Int) {
    mPostItems!!.removeAt(position)
    notifyDataSetChanged()
}

fun getlist(positionIndex: Int): UserMoneyRequest {
    return mPostItems!![positionIndex]
}

fun removeLoading() {
    isLoaderVisible = false
    val position = mPostItems!!.size - 1
    val item: UserMoneyRequest = getItem(position)
    if (item.id == "-1") {
        mPostItems!!.removeAt(position)
        notifyItemRemoved(position)
    }
}

fun clear() {
    mPostItems!!.clear()
    notifyDataSetChanged()
}

fun getItem(position: Int): UserMoneyRequest {
    return mPostItems!![position]
}

inner class ViewHolder internal constructor(itemView: View?) :
    BaseViewHolder(itemView) {
    private val tvStatus = itemView!!.findViewById(R.id.requestStatus) as TextView
    val tvAmount = itemView!!.findViewById(R.id.requestAmount) as TextView

    private val tvDate = itemView!!.findViewById(R.id.requestDateAndTime) as TextView
    private val requestedFrom = itemView!!.findViewById(R.id.requestedFromId) as TextView
    private val requestAccept = itemView!!.findViewById(R.id.requestAcceptStatus) as TextView
    private val requestDecline = itemView!!.findViewById(R.id.requestDecline) as TextView
    private val requestNotes = itemView!!.findViewById(R.id.requestNotes) as TextView

    val context: Context = itemView!!.context

    override fun clear() {}

    override fun onBind(position: Int) {
        super.onBind(position)
        val moneyRequest = mPostItems!![position]
        tvAmount.text = (moneyRequest.amount.toDouble() / 100).toString() + moneyRequest.user_account.currency.code
        tvDate.text = getMonthDateTime(moneyRequest.created_at)

        requestedFrom.text = moneyRequest.user_account.user!!.email
        requestNotes.text = "Notes: " + moneyRequest.notes

        setStatus(context, moneyRequest)

        //first on clicklistener
        requestAccept.setOnClickListener {
            recItemClick!!.onAcceptReqest(position, moneyRequest)
        }

        //second on clicklistener
        requestDecline.setOnClickListener {
            recItemClick!!.onCancelReqest(position, moneyRequest)
        }

    }

    @RequiresApi(Build.VERSION_CODES.O)
    private fun setStatus(context: Context, moneyRequest: UserMoneyRequest) {
        when (moneyRequest.status) {
            "0" -> {
                tvStatus.text = moneyRequest.statusStr
                tvStatus.setBackgroundResource(R.drawable.request_pending_text_bg)
                requestAccept.visibility = View.VISIBLE
                requestAccept.isClickable = true
                requestDecline.visibility = View.VISIBLE
                requestDecline.isClickable = true
            }
            "1" -> {
                tvStatus.text = moneyRequest.statusStr
                tvStatus.setBackgroundResource(R.drawable.request_active_background_text)
            }
            "2" -> {
                tvStatus.text = moneyRequest.statusStr
                tvStatus.setTextColor(
                    ContextCompat.getColor(
                        context,
                        R.color.color_status_rejected
                    )
                )
                tvStatus.setBackgroundResource(R.drawable.request_canceled_text_background)
            }
            "3" -> {
                tvStatus.text = moneyRequest.statusStr
                tvStatus.setBackgroundResource(R.drawable.request_rejected_text_background)
            }
            "4" -> {
                tvStatus.text = moneyRequest.statusStr
                tvStatus.setBackgroundResource(R.drawable.request_completed_text_background)
            }
        }
    }
}

inner class ProgressHolder internal constructor(itemView: View?) :
    BaseViewHolder(itemView) {
    override fun clear() {}
}

}

我的回收站视图的根元素

 <?xml version="1.0" encoding="utf-8"?>
 <androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 xmlns:app="http://schemas.android.com/apk/res-auto">

<RelativeLayout
    android:id="@+id/relPayoutRequestItem"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <LinearLayout
        android:id="@+id/detailsLayout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_marginTop="@dimen/_10sdp"
        android:layout_marginBottom="@dimen/_4sdp"
        android:layout_toStartOf="@+id/amountLayout"
        android:orientation="vertical"
        android:padding="@dimen/_6sdp">

        <TextView
            android:id="@+id/requestedFromId"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ellipsize="end"
            android:fontFamily="@font/spartanmbbold"
            android:lineSpacingExtra="@dimen/_4sdp"
            android:lines="1"
            android:text="@string/dummy_text_transfers"
            android:textColor="@color/text_color"
            android:textSize="@dimen/_10sdp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/requestNotes"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/_2sdp"
            android:fontFamily="@font/spartanmb_semibold"
            android:lineSpacingExtra="@dimen/_4sdp"
            android:text="Notes: NIL"
            android:textColor="@color/text_color"
            android:textSize="@dimen/_10sdp"
            android:textStyle="normal" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/amountLayout"
        android:layout_marginTop="@dimen/_14sdp"
        android:layout_marginBottom="@dimen/_4sdp"
        android:layout_marginLeft="@dimen/_10sdp"
        android:layout_marginRight="@dimen/_10sdp"
        android:layout_alignParentEnd="true"
        android:orientation="vertical"
        android:layout_width="@dimen/_68sdp"
        android:layout_height="wrap_content">

        <TextView
            android:id="@+id/requestAmount"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:fontFamily="@font/spartan_mb_medium"
            android:textStyle="bold"
            android:lines="1"
            android:ellipsize="end"
            android:textSize="@dimen/_10sdp"
            android:layout_gravity="center_vertical|end"
            android:textColor="@color/text_color"
            android:lineSpacingExtra="@dimen/_4sdp"
            android:text="@string/dummy_transaction_amount"/>

    </LinearLayout>

    <RelativeLayout
        android:id="@+id/bottomlayout"
        android:layout_below="@+id/detailsLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >

        <TextView
            android:id="@+id/requestDateAndTime"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentStart="true"
            android:layout_centerVertical="true"
            android:layout_marginStart="@dimen/_6sdp"
            android:layout_marginTop="@dimen/_12sdp"
            android:ellipsize="end"
            android:fontFamily="@font/spartan_mb_medium"
            android:lineSpacingExtra="@dimen/_6sdp"
            android:lines="1"
            android:text="@string/dummy_transfer_time"
            android:textColor="@color/transaction_time_text_color"
            android:textSize="@dimen/_8sdp"
            android:textStyle="normal" />

        <TextView
            android:layout_centerVertical="true"
            android:id="@+id/requestStatus"
            android:layout_toStartOf="@+id/acceptRipple"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:fontFamily="@font/spartanmbbold"
            android:textStyle="bold"
            android:layout_marginEnd="@dimen/_4sdp"
            android:lines="1"
            android:gravity="center"
            android:layout_gravity="end"
            android:textSize="@dimen/_8sdp"
            android:textColor="@color/white"
            android:lineSpacingExtra="@dimen/_6sdp"
            android:text="@string/dummy_payment_method"/>

        <!-- first view for clicklistener-->
        <com.balysv.materialripple.MaterialRippleLayout
            android:id="@+id/acceptRipple"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginTop="@dimen/_6sdp"
            android:layout_marginEnd="@dimen/_4sdp"
            app:mrl_rippleAlpha="0.2"
            android:layout_toStartOf="@+id/requestRippleDecline"
            app:mrl_rippleColor="@color/ripple_black"
            app:mrl_rippleHover="true"
            app:mrl_rippleOverlay="true"
            app:mrl_rippleRoundedCorners="@dimen/_12sdp">

            <TextView
                android:id="@+id/requestAcceptStatus"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:fontFamily="@font/spartanmbbold"
                android:textStyle="bold"
                android:visibility="gone"
                android:lines="1"
                android:gravity="center"
                android:layout_gravity="end"
                android:background="@drawable/user_request_active_background_text"
                android:textSize="@dimen/_8sdp"
                android:textColor="@color/white"
                android:lineSpacingExtra="@dimen/_6sdp"
                android:text="@string/accept"/>

        </com.balysv.materialripple.MaterialRippleLayout>

       <!-- second view for clicklistener-->
        <com.balysv.materialripple.MaterialRippleLayout
            android:id="@+id/requestRippleDecline"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentEnd="true"
            android:layout_centerVertical="true"
            android:layout_marginTop="@dimen/_6sdp"
            android:layout_marginEnd="@dimen/_10sdp"
            app:mrl_rippleAlpha="0.2"
            app:mrl_rippleColor="@color/ripple_black"
            app:mrl_rippleHover="true"
            app:mrl_rippleOverlay="true"
            app:mrl_rippleRoundedCorners="@dimen/_12sdp">

            <TextView
                android:id="@+id/requestDecline"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:fontFamily="@font/spartanmbbold"
                android:textStyle="bold"
                android:lines="1"
                android:background="@drawable/user_request_rejected_text_background"
                android:gravity="center"
                android:visibility="gone"
                android:layout_gravity="end"
                android:textSize="@dimen/_8sdp"
                android:textColor="@color/white"
                android:lineSpacingExtra="@dimen/_6sdp"
                android:text="@string/decline"/>

        </com.balysv.materialripple.MaterialRippleLayout>

    </RelativeLayout>

    <View
        android:layout_marginStart="@dimen/_20sdp"
        android:layout_marginEnd="@dimen/_15sdp"
        android:layout_marginTop="@dimen/_10sdp"
        android:layout_below="@+id/bottomlayout"
        android:layout_width="match_parent"
        android:layout_height="@dimen/_1sdp"
        android:background="@color/settings_screen_seperator" />
</RelativeLayout>

</androidx.cardview.widget.CardView>

【问题讨论】:

标签: android android-fragments android-recyclerview interface onclicklistener


【解决方案1】:

请检查下面的代码,它是写在 kotlin 上的,如果你想用 java 写,请告诉我,我会分享。

class LocationAdapter (
private val list: List<Any>,
private val listener: ClickItemListener
) :
RecyclerView.Adapter<LocationAdapter.ViewHolder>() {

interface ClickItemListener {
    fun onClicked(model: Any,position:Int)
}


override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
    return ViewHolder(ItemLocationBinding.inflate(LayoutInflater.from(parent.context)))

}

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

override fun onBindViewHolder(holder: ViewHolder, parentPosition: Int) {

    Timber.d("onBindViewHolder" + parentPosition)
    val model = list.get(parentPosition)

    holder.bind.name.text = model.name

    holder.itemView.setOnClickListener {
        listener.onClicked(model,parentPosition)
    }
}

inner class ViewHolder(private var binding: ItemLocationBinding) :
    RecyclerView.ViewHolder(binding.root) {
    val bind = binding
}

}

//call in Activity or Fragment
locationList.adapter = LocationAdapter(sharedViewModel.listOfPlace,
        object : LocationAdapter.ClickItemListener {
            override fun onClicked(model: Any, position: Int) {
                Timber.d("$position")
            }
        })

【讨论】:

    【解决方案2】:

    你可以试试这个方法:

    class YourAdapter(private val onItemClick: (String) -> Unit) {
    ...
    } 
    

    然后在你的onBindViewHolder

    override fun onBindViewHolder(holder: YourViewHolder, position: Int) {
            holder.bind(
                ...,
                onItemClick,
                ...,
            )
        }
    

    然后在你的视图持有者绑定方法

    fun bind(onItemClick: (String) -> Unit) {
       onItemClick("Whatever")
    }
    

    然后你创建你的适配器有这个:

     val yourAdapter =
                YourAdapter { test ->
                    //Here you'd get "Whatever" as string since is what you have in your ViewHolder
                }
    

    如果您需要通知 Activity,那么您必须在 Fragment 和 Activity 之间进行回调,或者只是进行强制转换(不推荐)并调用您想要的方法。

    这样做的例子(还有更多方法) https://gist.github.com/zacharymikel/40aa61b2ff4d0b1ae267212d7dd965e5 https://tutorial.eyehunts.com/android/activity-and-fragments-communication/

    【讨论】:

    • 问题是它在活动中完美地工作,甚至在片段中的一些时间但没有有效..
    • 您在哪里创建适配器?将它放在super.onViewCreated() 之后的onViewCreated() 中,它应该可以工作。 (在片段中)
    • 我已经检查过了,可能我真的需要改变我的适配器而不是......但我添加了很多东西,比如分页和逻辑。并且单击按钮在列表中并不总是可见。那么我可能没有管理我的回收站视图的状态吗?
    • 我尝试了您的解决方案,但没有帮助
    【解决方案3】:

    问题出在视图中,我使用的是嵌套滚动视图,它没有生成点击监听器

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-28
      • 2017-05-22
      • 1970-01-01
      • 2016-06-02
      • 1970-01-01
      相关资源
      最近更新 更多