In the previous tutorial we have seen example
In this tutorial we will see how to fill swiped Portion using canvas by drawing text and svg image resource .
Add RecyclerView to your layout
file : activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/rcv"/>
Data Class
file : Model.kt
package com.tutorialsbuzz.recyclerview data class Model(val name: String, val version: String) {}
To Load Data Into RecyclerView , We will read JSON File Kept Inside Asset folder and map it to above defined data class .
file : main\assets\android_version.json
[ { "name": "Cupcake", "version": "Android 1.5" }, { "name": "Donut", "version": "Android 1.6" }, { "name": "Eclairs", "version": "Android 2.0-2.1" }, { "name": "Froyo", "version": "Android 2.2-2.3" }, { "name": "Gingerbread", "version": "Android 2.3-2.3.7" }, { "name": "Honeycomb", "version": "Android 3.0-3.2.6" }, { "name": "Icecream", "version": "Android 4.0-4.0.4" }, { "name": "Jellybean", "version": "Android 4.1-4.3.1" }, { "name": "Kitkat", "version": "Android 4.4-4.4.4" }, { "name": "Lolipop", "version": "Android 5.0-5.1.1" }, { "name": "Marshmallow", "version": "Android 6.0-6.0.1" }, { "name": "Nougat", "version": "Android 7.0-7.1.2" }, { "name": "Oreo", "version": "Android 8.0-8.1" }, { "name": "Pie", "version": "Android 9.0" } ]
Adapter and ViewHolder For RecyclerView .
1. XML Layout For RecyclerView Item
Create XML Layout file in res/layout and name it row_item.xml , This Layout defines the layout for Items of RecyclerView . Here In this example we have two TextView inside LinearLayout
file : row_item.xml
<?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:padding="20dp" android:layout_height="wrap_content"> <TextView android:id="@+id/txt" android:textSize="22sp" android:layout_width="match_parent" android:layout_height="wrap_content" android:textStyle="bold"/> <TextView android:id="@+id/sub_txt" android:textSize="18sp" android:layout_width="match_parent" android:layout_height="wrap_content" android:textStyle="italic"/> </LinearLayout>
2. Adapter and ViewHolder
- Create a Adapter That RecyclerView Can Use , Create a class CustomAdapter extend it to RecyclerView.Adapter .
- Create Inner class ViewHolder extend it to RecyclerView.ViewHolder
package com.tutorialsbuzz.recyclerview import android.content.Context import android.os.Handler import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.tutorialsbuzz.recyclerviewswipecanvas.R import kotlinx.android.synthetic.main.row_item.view.* class CustomAdapter(val modelList: List<Model>, val context: Context) : RecyclerView.Adapter<RecyclerView.ViewHolder>() { var handler: Handler? = Handler() override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { (holder as ViewHolder).bind(modelList.get(position)); } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { val layoutInflater = LayoutInflater.from(parent.context) return ViewHolder(layoutInflater.inflate(R.layout.row_item, parent, false)) } override fun getItemCount(): Int { return modelList.size; } inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { fun bind(model: Model): Unit { itemView.txt.text = model.name itemView.sub_txt.text = model.version } } fun undoView(position: Int) { handler?.postDelayed({ notifyItemChanged(position) }, 1000) } }
ItemTouchHelper CallBack For RecyclerView
Create an abstract class SwipeToDeleteCallback extend this class to ItemTouchHelper.SimpleCallback .
- onSwiped : Called when a ViewHolder is swiped by the user. At this point, you should update your adapter (e.g. remove the item) and call related Adapter notify event.
- getSwipeDirs : This callback Returns the swipe directions for the provided ViewHolder.
(To disable swipe at particular viewholder return to ItemTouchHelper.ACTION_STATE_IDLE) - onChildDraw : Called by ItemTouchHelper on RecyclerView's onDraw callback.If you would like to customize how your View's respond to user interactions, this is a good place to override.
Drawing to Canvas On Left Right Swipe
Inside onChildDraw Callback of ItemTouchHelper.SimpleCallback , We will fill swiped portion using canvas .
override fun onChildDraw( c: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean){
................
...........
}
................
...........
}
We will use the below two parameter for drawing to canvas and to decide on which direction (left or right).
- If dx < 0 then it is considered as left swipe .
- If dx > 0 then it is considered as right swipe .
- colorCanavas : call this to add background to canvas by passing colorCode and proper bound co-ordinates(left,top,right,bottom).
- drawTextOnCanvas : call this to add text to canvas by passing string and x-coordinate,y-coordinate
- drawIconOnCanVas : call this to add icon to canvas by passing bitmap and and proper bound co-ordinates(left,top,right,bottom).
package com.tutorialsbuzz.recylerviewswipetodelete import android.content.Context import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable import android.util.Log import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView abstract class SwipeToDeleteCallback : ItemTouchHelper.SimpleCallback { //configure left swipe params var leftBG: Int = Color.LTGRAY var leftLabel: String = "" var leftIcon: Drawable? = null //configure right swipe params var rightBG: Int = Color.LTGRAY; var rightLabel: String = "" var rightIcon: Drawable? = null var context: Context; constructor(context: Context, dragDir: Int, swipeDir: Int) : super(dragDir, swipeDir) { this.context = context } private lateinit var background: Drawable var initiated: Boolean = false //Setting Swipe Text val paint = Paint() fun initSwipeView(): Unit { paint.setColor(Color.WHITE) paint.setTextSize(48f) paint.setTextAlign(Paint.Align.CENTER) background = ColorDrawable(); initiated = true; } override fun onMove( recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder ): Boolean { return false } override fun onChildDraw( c: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean ) { Log.d("onChildDraw", "dx: " + dX) val itemView = viewHolder.itemView if (!initiated) { initSwipeView() } if (dX != 0.0f) { if (dX > 0) { //right swipe val intrinsicHeight = (rightIcon?.getIntrinsicWidth() ?: 0) val xMarkTop = itemView.top + ((itemView.bottom - itemView.top) - intrinsicHeight) / 2 val xMarkBottom = xMarkTop + intrinsicHeight colorCanavas(c, rightBG, itemView.left + dX.toInt(), itemView.top, itemView.left, itemView.bottom) drawTextOnCanvas(c, rightLabel, (itemView.left + 200).toFloat(), (xMarkTop + 10).toFloat()) drawIconOnCanVas( c, rightIcon, itemView.left + (rightIcon?.getIntrinsicWidth() ?: 0) + 50, xMarkTop + 20, itemView.left + 2 * (rightIcon?.getIntrinsicWidth() ?: 0) + 50, xMarkBottom + 20 ) } else { //left swipe val intrinsicHeight = (leftIcon?.getIntrinsicWidth() ?: 0) val xMarkTop = itemView.top + ((itemView.bottom - itemView.top) - intrinsicHeight) / 2 val xMarkBottom = xMarkTop + intrinsicHeight colorCanavas( c, leftBG, itemView.right + dX.toInt(), itemView.top, itemView.right, itemView.bottom ) drawTextOnCanvas(c, leftLabel, (itemView.right - 200).toFloat(), (xMarkTop + 10).toFloat()) drawIconOnCanVas( c, leftIcon, itemView.right - 2 * (leftIcon?.getIntrinsicWidth() ?: 0) - 70, xMarkTop + 20, itemView.right - (leftIcon?.getIntrinsicWidth() ?: 0) - 70, xMarkBottom + 20 ) } } super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive) } fun colorCanavas(canvas: Canvas, canvasColor: Int, left: Int, top: Int, right: Int, bottom: Int): Unit { (background as ColorDrawable).color = canvasColor background.setBounds(left, top, right, bottom) background.draw(canvas) } fun drawTextOnCanvas(canvas: Canvas, label: String, x: Float, y: Float) { canvas.drawText(label, x, y, paint) } fun drawIconOnCanVas( canvas: Canvas, icon: Drawable?, left: Int, top: Int, right: Int, bottom: Int ): Unit { icon?.setBounds(left, top, right, bottom) icon?.draw(canvas) } }
Configure left swipe and right swipe
Inside SwipeToDeleteCallback declare variable for which is responsible drawing background ,label ,icon inside canvas .
1. Left Swipe Configuration
//configure left swipe params var leftBG: Int = Color.LTGRAY var leftLabel: String = "" var leftIcon: Drawable? = null //configure left swipe swipeToDeleteCallback.leftBG = ContextCompat.getColor(this, R.color.leftSwipeBG) swipeToDeleteCallback.leftLabel = "Thumbs UP" swipeToDeleteCallback.leftIcon = AppCompatResources. getDrawable(this, R.drawable.ic_thumb_up_black_24dp)
2. Right Swipe Configuration
//configure right swipe params var rightBG: Int = Color.LTGRAY; var rightLabel: String = "" var rightIcon: Drawable? = null //configure right swipe swipeToDeleteCallback.rightBG = ContextCompat.getColor(this, R.color.rightSwipeBG) swipeToDeleteCallback.rightLabel = "Thumbs Down" swipeToDeleteCallback.rightIcon = AppCompatResources. getDrawable(this, R.drawable.ic_thumb_down_black_24dp)
Activity
- Create a koltin class MainActivity.kt and extend it to AppCompatActivity class .
- Override onCreate function and set the content of this MainActivity with above defined xml layout (activity_main.xml).
- Read JSON Data From Asset Folder , this will be used for binding data into RecyclerView .
- Set Vertical Linear LayoutManager to RecyclerView.
- Create Instance of Adapter and set to RecyclerView .
- Add CustomItemDecortion to RecyclerView .
- Create an instance of ItemTouchHelper by passing SwipeToDeleteCallback as parameter to its constructor.
- Attach ItemTouchHelper to RecyclerView .
file : MainActivity.kt
package com.tutorialsbuzz.recyclerviewswipecanvas import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.content.res.AppCompatResources import androidx.core.content.ContextCompat import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.tutorialsbuzz.recyclerview.CustomAdapter import com.tutorialsbuzz.recyclerview.Model import com.tutorialsbuzz.recylerviewswipetodelete.SwipeToDeleteCallback import kotlinx.android.synthetic.main.activity_main.* import org.json.JSONArray import org.json.JSONObject class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) rcv.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false) val model = readFromAsset(); val adapter = CustomAdapter(model, this) rcv.adapter = adapter; rcv.addItemDecoration(SimpleDividerItemDecoration(this)) val swipeToDeleteCallback = object : SwipeToDeleteCallback(this, 0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) { override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { adapter.undoView(viewHolder.adapterPosition) } } //configure left swipe swipeToDeleteCallback.leftBG = ContextCompat.getColor(this, R.color.leftSwipeBG) swipeToDeleteCallback.leftLabel = "Thumbs UP" swipeToDeleteCallback.leftIcon = AppCompatResources.getDrawable(this, R.drawable.ic_thumb_up_black_24dp) //configure right swipe swipeToDeleteCallback.rightBG = ContextCompat.getColor(this, R.color.rightSwipeBG) swipeToDeleteCallback.rightLabel = "Thumbs Down" swipeToDeleteCallback.rightIcon = AppCompatResources.getDrawable(this, R.drawable.ic_thumb_down_black_24dp) val itemTouchHelper = ItemTouchHelper(swipeToDeleteCallback) itemTouchHelper.attachToRecyclerView(rcv) } private fun readFromAsset(): List<Model> { val modeList = mutableListOf<Model>() val bufferReader = application.assets.open("android_version.json").bufferedReader() val json_string = bufferReader.use { it.readText() } val jsonArray = JSONArray(json_string); for (i in 0..jsonArray.length() - 1) { val jsonObject: JSONObject = jsonArray.getJSONObject(i) val model = Model(jsonObject.getString("name"), jsonObject.getString("version")) modeList.add(model) } return modeList } }
No comments:
Post a Comment