首页 > 解决方案 > Android在每10个项目(如tumblr)的recyclerview下方添加背景视图

问题描述

我正在尝试制作像 tumblr 应用程序这样的回收站视图。你可以在这里看到:https ://streamable.com/s/gpyec/kxvjnz

我的问题是如何在 recyclerview 下方添加视频(或任何可点击的)?我添加了一个项目装饰实现,如下所示:

class RecyclerViewAdItemDecoration(private val func:() -> Unit) : RecyclerView.ItemDecoration() {

  override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
    super.getItemOffsets(outRect, view, parent, state)
    val position = parent.getChildLayoutPosition(view)

    val mLayoutManager = parent.layoutManager
    if (mLayoutManager is GridLayoutManager) {
      setGridParams(view, position, parent)
    } else if (mLayoutManager is LinearLayoutManager) {
      setLinearParams(view, position, parent)
    }
  }

  private fun setGridParams(view: View, position: Int, parent: RecyclerView) {
    val p = view.layoutParams as ViewGroup.MarginLayoutParams
    if (position == 0) {
      p.setMargins(0,0,0, 0)
    } else if (position >= 10 && (position % 10 == 0 || position % 11 == 0)) {
      p.setMargins(0,0,0, parent.height)
      func()
    } else {
      p.setMargins(0,0,0, 0)
    }
  }

  private fun setLinearParams(view: View, position: Int, parent: RecyclerView) {
    val p = view.layoutParams as ViewGroup.MarginLayoutParams
    if (position == 0) {
      p.setMargins(0,0,0, 0)
    } else if (position >= 10 && (position % 10 == 0)) {
      p.setMargins(0,0,0, parent.height)
      func()
    } else {
      p.setMargins(0,0,0, 0)
    }
  }
}

这样我可以为背景视图添加足够的空间,但它现在不可点击。我也找不到任何用于这种实现的库。感谢任何帮助。

编辑:为了澄清,我想在回收站视图中的每 10 个项目之后显示背景视频(或任何视图)。就像在链接中的视频中看到的那样,在回收站视图中每 10 个项目之间有一个空格,这也会触发在后台播放视频(在回收站视图下方)

标签: androidandroid-recyclerview

解决方案


在回收站视图中每 10 个项目后立即显示背景视频(或任何视图)。

如果背景视频在每 10 项之后,则表示有一项(第 11 项),它是透明的。

您真正想要的是具有多种视图类型的 recyclerview


使用RelativeLayout允许activity_main.xml将视图放置在其他视图之上(在 Z 轴上)。

例如:RecyclerView是这里的最高视图。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:focusable="true">

    <View
        android:id="@+id/ad"
        android:background="@color/colorAccent"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_posts"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />

</RelativeLayout>

为两种类型的回收站视图类型创建两个项目布局

前任:

item_normal.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="100dp">
    <TextView
        android:id="@+id/tv_post"
        tools:text="Post"
        android:background="@android:color/white"
        android:textSize="32sp"
        android:gravity="center_horizontal|center_vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

item_transparent.xml(其中布局背景是透明的,可以看到表面区域下方的视图)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/transparent"/>

item_transparent中的设置android:clickable=false不会停止触发透明项目上的点击事件,因此使用接口的通信流,当点击透明项目时将另一个视图(广告)带到前面。

MainActivity.kt

class MainActivity : AppCompatActivity(), RvAdpater.OnItemClick {

    private lateinit var adView: View
    private lateinit var rvPosts: RecyclerView

    override fun onClick() {
        bringAdFront()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        rvPosts = findViewById(R.id.rv_posts)
        rvPosts.layoutManager = LinearLayoutManager(this)

        val rvAdpater = RvAdpater()
        rvAdpater.setListener(this)
        rvPosts.adapter = rvAdpater
    }

    private fun bringAdFront() {

        adView = findViewById<View>(R.id.ad)
        adView.bringToFront()
    }

    override fun onBackPressed() {
        // to go back to the normal recycler view when back button is pressed
        val parent = rvPosts.parent as ViewGroup
        parent.removeAllViews()
        parent.addView(adView, 0)
        parent.addView(rvPosts, 1)
    }
}

RvAdapter.kt

const val TAG = "RvAdpater"

class RvAdpater : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    private lateinit var listener:OnItemClick


    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val viewNormal = LayoutInflater.from(parent.context).inflate(R.layout.item_normal, parent, false)
        val viewTransparent = LayoutInflater.from(parent.context).inflate(R.layout.item_transparent, parent, false)

        return when(viewType){
            0 -> NormalViewHolder(viewNormal)
            2 -> TransparentViewHolder(viewTransparent)
            else -> NormalViewHolder(viewNormal)
        }

    }

    override fun getItemCount(): Int = 10

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {

        when(getItemViewType(position)){
            0 -> {
                val normalHolder = holder as NormalViewHolder
                normalHolder.tv.text = "Post"
                normalHolder.itemView.setOnClickListener {
                    Log.d(TAG, "Clicked on Normal item")
                }
            }
            2 -> {
                val transparentHolder = holder as TransparentViewHolder
                transparentHolder.itemView.setOnClickListener {

                    listener.onClick()
                }
            }
        }
    }

    fun setListener(onItem:OnItemClick){
        listener = onItem
    }

    interface OnItemClick{

        fun onClick()
    }

    override fun getItemViewType(position: Int): Int = position % 2 * 2

    class NormalViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
        val tv:TextView = itemView.findViewById(R.id.tv_post)
    }

    class TransparentViewHolder(itemView: View): RecyclerView.ViewHolder(itemView)
}

查看repo以获取工作示例


为了处理多种视图类型,您可以使用Epoxy库。


推荐阅读