0

I'm currently trying to make a scrollable grid of ScratchViews, but the views that have already been scratched by the user, are appearing as not scratched when the user scrolls down and back up again, because the adapter is repainting each of the views back to their original unscratched state.

I've tried the solutions posted here: I want my RecyclerView to not recycle some items, but preventing the views from being recycled apparently doesn't prevent them from being redrawn.

Here is my code:

Fragment:

class ScratchOffGameFragment : Fragment() { 

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_scratch_off_game, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        var data = ArrayList<ScratchOffGameItem>()

        for (i in 1..20) {
            var aux = ScratchOffGameItem()
            data.add(aux)
        }

        scratchOffGameRecycle.layoutManager = GridLayoutManager(context, 3)
        val scratchOffGameAdapter = ScratchOffGameAdapter(activity!!,data)

       scratchOffGameRecycle.recycledViewPool.setMaxRecycledViews(1,0);
       scratchOffGameRecycle.adapter = scratchOffGameAdapter
    }

Adapter:

class ScratchOffGameAdapter(var context: Context, private val mData: ArrayList<ScratchOffGameItem>) : RecyclerView.Adapter<ScratchOffGameAdapter.ViewHolder>() {

    private val mInflater: LayoutInflater = LayoutInflater.from(context)
    inner class ViewHolder internal constructor(itemView: View) : RecyclerView.ViewHolder(itemView)

    @NonNull
    override fun onCreateViewHolder(@NonNull parent: ViewGroup, viewType: Int): ViewHolder {
        val view = mInflater.inflate(R.layout.scratch_off_game_item, parent, false)
        return ViewHolder(view)
    }


    // binds the data to the TextView in each cell
    override fun onBindViewHolder(@NonNull holder: ViewHolder, position: Int) {
        holder.setIsRecyclable(false)
    }

    override fun onViewAttachedToWindow(holder: ViewHolder) {
        super.onViewAttachedToWindow(holder)
        ScratchoffController(context)
            .setThresholdPercent(0.80)
            .setTouchRadiusDip(context, 30)
            .attach(holder.itemView.scratch_view, holder.itemView.scratch_view_behind)

    }

    // total number of cells
    override fun getItemCount(): Int {
        return mData.size
    }


    override fun getItemViewType(position: Int): Int {
        return 1
    }

}

Item being painted by the adapter (scratch_off_game_item.xml):

<FrameLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/achievementItem"
    android:layout_width="110dp"
    android:layout_height="90dp"
    android:layout_gravity="center_horizontal"
    android:layout_marginLeft="30dp"
    android:layout_marginTop="20dp"
    android:layout_marginRight="30dp"
    android:background="@drawable/achievements_border">

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >

        <RelativeLayout
            android:id="@+id/scratch_view_behind"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/white" >

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:fontFamily="@font/zing_rust_demo_base"
                android:gravity="center"
                android:text="20"
                android:textColor="@color/black"
                android:textSize="24sp"
                android:layout_centerInParent="true"/>
        </RelativeLayout>

        <com.jackpocket.scratchoff.views.ScratchableLinearLayout
            android:id="@+id/scratch_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:background="@color/gold" >
            <ImageView
                android:layout_width="73dp"
                android:layout_height="42dp"
                android:src="@drawable/scratch_here_ic" />
        </com.jackpocket.scratchoff.views.ScratchableLinearLayout>
    </RelativeLayout>
</FrameLayout>

And RecyclerView:

<android.support.v7.widget.RecyclerView
    android:id="@+id/scratchOffGameRecycle"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_below="@id/youWin"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="10dp"
    android:layout_marginRight="50dp"
    android:layout_marginBottom="10dp"
    android:background="@drawable/bg_gold_rectangle"
    android:columnWidth="100dp"
    android:numColumns="3" />

As additional information, the libraries that I've tried using are these: 'com.jackpocket:scratchoff:1.3.0', 'com.github.cooltechworks:ScratchView:v1.1'in conjuction with both recycler and grid views to no avail.

Ivan
  • 1,265
  • 11
  • 20

1 Answers1

0

What I ended up doing was changing the scratchoff library to this one: 'com.goibibo.libs:scratchcardview:0.1.6' ('com.jackpocket:scratchoff:1.3.0' had problems setting the listener inside the OnBindViewHolder method) and making a compromise to only save fully scratched views and not partially scratched ones. Here are the modifications I made:

OnBindViewHolder:

override fun onBindViewHolder(@NonNull holder: ViewHolder, position: Int) {
    holder.itemView.number.text = mData[position].number
    var scratchRelativeLayoutView = holder.itemView.scratch_card
    holder.setIsRecyclable(false)

    if(mData[position].isScratched && scratchRelativeLayoutView!=null) {
        scratchRelativeLayoutView.visibility = View.GONE
        holder.itemView.numberHidden.text = mData[position].number
        holder.itemView.numberHidden.visibility = View.VISIBLE
    }
    else {
        scratchRelativeLayoutView.setStrokeWidth(5)
        scratchRelativeLayoutView.setScratchView(R.layout.lyt_scratch) // scratchable layout
        scratchRelativeLayoutView.setRevealListener(object : ScratchRelativeLayoutView.IRevealListener {
            override fun onRevealed(tv: ScratchRelativeLayoutView) {
                mData[position].isScratched = true
            }

            override fun onRevealPercentChangedListener(siv: ScratchRelativeLayoutView, percent: Float) {
                if (percent>0.5) {
                    siv.reveal()
                }
            }
        })
    }
}

scratch_off_game_item.xml

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/achievementItem"
    android:layout_width="90dp"
    android:layout_height="90dp">

    <TextView
        android:id="@+id/numberHidden"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fontFamily="@font/zing_rust_demo_base"
        android:gravity="center"
        android:text="23"
        android:background="@color/white_scratch_off"
        android:textColor="@color/black"
        android:textSize="24sp"
        android:layout_gravity="center"/>

    <com.goibibo.libs.views.ScratchRelativeLayoutView
        android:id="@+id/scratch_card"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/white_scratch_off">

        <TextView
            android:id="@+id/number"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:fontFamily="@font/zing_rust_demo_base"
            android:gravity="center"
            android:textColor="@color/black"
            android:textSize="24sp"
            android:layout_centerInParent="true"/>
     </com.goibibo.libs.views.ScratchRelativeLayoutView>
 </FrameLayout>
Ivan
  • 1,265
  • 11
  • 20