0

I am trying to make a recycler view like tumblr app. You can see here: https://streamable.com/s/gpyec/kxvjnz

My question is how to add a video (or any clickable) below recyclerview? I added an item decoration implementation as follows:

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)
    }
  }
}

This way I could add enough space for background view but it's not clickable now. I also couldn't find any library for such implementation. Appreciated for any help.

Edit: To clarify, I want to show background video (or any view) right after every 10th item in recycler view. Like it's seen in video in the link, there is a space between every 10 item in recycler view, which also triggers to play the video in the background (below recycler view)

Ali Yucel Akgul
  • 1,101
  • 8
  • 27
  • 53

1 Answers1

1

show background video (or any view) right after every 10th item in recycler view.

If the background video is after every 10th item, it means there is an item (11th), which is transparent.

What you actually want here is recyclerview with multiple view types.


Use a RelativeLayout for activity_main.xml which allows to place views on top of others (in Z axis).

ex: RecyclerView is the top most view here.

<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>

Create two item layouts for two types of recycler view types

ex:

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 (where layout background is transparent that allow to see the view below the surface area)

<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"/>

Setting android:clickable=false in item_transparent does not stop triggering the click event on transparent item, so use communication flow using interfaces, to bring the other view(ad) to the front when clicked on transparent item.

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)
}

Checkout the repo for an working example


For handling multiple view types, you may use Epoxy library.

user158
  • 12,852
  • 7
  • 62
  • 94
  • thanks for your comment. But your way doesn't work. As you can see in the video, even though you create a another view for background video it'll be part of recycler view data. What I want to achieve is to let it in the background and make the recycler work with it's own data. – Ali Yucel Akgul Sep 06 '19 at 14:14
  • actually you have not read clearly. video view is just in the background, its not a part of the recyclerview. – user158 Sep 06 '19 at 15:07
  • will be able to click on video? because I guess recycler view will prevent it. – Ali Yucel Akgul Sep 06 '19 at 20:47
  • updated the answer, trick is to make: transparent item `android:clickable="false"` – user158 Sep 07 '19 at 01:45
  • Just tried your solution, added android:clickable="false" to my transparent item, but still unable to click on background view. To test better I've added a simple button but it doesn't handle clicks (doesn't receive) – Ali Yucel Akgul Sep 09 '19 at 14:00
  • @AliYucelAkgul check whether recyclerview consumes the clicks by setting a `onClick` on recyclerview. If so please set it `clickable="false"`. Let me know how it goes – user158 Sep 10 '19 at 01:27
  • I set clickable to false. Still background view is not receiving clicks. – Ali Yucel Akgul Sep 10 '19 at 15:54
  • @AliYucelAkgul If you can share a sample repo, I may be able to help – user158 Sep 11 '19 at 01:38
  • fixed your issue, added sample repo. please upvote and mark the answer as correct – user158 Sep 14 '19 at 08:32
  • in your code, user needs to click on back button to return back to previous state, which is not correct. If you checked the video, background is still there and user is still able to swipe un/down. – Ali Yucel Akgul Oct 04 '19 at 17:18
  • yes user need to click back button if they click the transparent item(video ad in your case), since it become main focus (if a user click an ad it means they want to know see it in fullscreen without any disturbances). otherwise user could scroll usually similar to your video – user158 Oct 05 '19 at 02:56