Skip to main content

Simplify Your Tax Calculations with GST Calculator 2024: The Ultimate Tool for Businesses and Individuals

Recycler View Like Google Play Store App | How to use SnapHelper Android, Kotlin

 If we see the google play store android app, we can see that the app list in horizontal recycler view hold a property that the first property hold always full visible or not visible, but a portion visible is not seeing.




This property is snap property. In this article I show you how to use it in our own application. Basically we use two type of snap. Center Snap and start snap. I show you both here. So read full article here.

The Key Moment code is here-

For center snap you need to write 2 lines code-

        //center Snap
        val snapHelper = LinearSnapHelper()
        snapHelper.attachToRecyclerView(recyclerView1)


For start snap, create a class in kotlin say StartSnapHelper.kt

package com.example.snaphelpersampleapp

import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearSnapHelper
import androidx.recyclerview.widget.OrientationHelper
import androidx.recyclerview.widget.RecyclerView

class StartSnapHelper : LinearSnapHelper() {
    private var mVerticalHelper: OrientationHelper? = null
    private var mHorizontalHelper: OrientationHelper? = null
    @Throws(IllegalStateException::class)
    override fun attachToRecyclerView(recyclerView: RecyclerView?) {
        super.attachToRecyclerView(recyclerView)
    }

    override fun calculateDistanceToFinalSnap(
        layoutManager: RecyclerView.LayoutManager,
        targetView: View
    ): IntArray? {
        val out = IntArray(2)
        if (layoutManager.canScrollHorizontally()) {
            out[0] = distanceToStart(targetView, getHorizontalHelper(layoutManager))
        } else {
            out[0] = 0
        }
        if (layoutManager.canScrollVertically()) {
            out[1] = distanceToStart(targetView, getVerticalHelper(layoutManager))
        } else {
            out[1] = 0
        }
        return out
    }

    override fun findSnapView(layoutManager: RecyclerView.LayoutManager): View? {
        return if (layoutManager is LinearLayoutManager) {
            if (layoutManager.canScrollHorizontally()) {
                getStartView(layoutManager, getHorizontalHelper(layoutManager))
            } else {
                getStartView(layoutManager, getVerticalHelper(layoutManager))
            }
        } else super.findSnapView(layoutManager)
    }

    private fun distanceToStart(targetView: View, helper: OrientationHelper?): Int {
        return helper!!.getDecoratedStart(targetView) - helper.startAfterPadding
    }

    private fun getStartView(
        layoutManager: RecyclerView.LayoutManager,
        helper: OrientationHelper?
    ): View? {
        if (layoutManager is LinearLayoutManager) {
            val firstChild = layoutManager.findFirstVisibleItemPosition()
            val isLastItem = (layoutManager
                .findLastCompletelyVisibleItemPosition()
                    == layoutManager.getItemCount() - 1)
            if (firstChild == RecyclerView.NO_POSITION || isLastItem) {
                return null
            }
            val child = layoutManager.findViewByPosition(firstChild)
            return if (helper!!.getDecoratedEnd(child) >= helper.getDecoratedMeasurement(child) / 2
                && helper.getDecoratedEnd(child) > 0
            ) {
                child
            } else {
                if (layoutManager.findLastCompletelyVisibleItemPosition()
                    == layoutManager.getItemCount() - 1
                ) {
                    null
                } else {
                    layoutManager.findViewByPosition(firstChild + 1)
                }
            }
        }
        return super.findSnapView(layoutManager)
    }

    private fun getVerticalHelper(layoutManager: RecyclerView.LayoutManager): OrientationHelper? {
        if (mVerticalHelper == null) {
            mVerticalHelper = OrientationHelper.createVerticalHelper(layoutManager)
        }
        return mVerticalHelper
    }

    private fun getHorizontalHelper(layoutManager: RecyclerView.LayoutManager): OrientationHelper? {
        if (mHorizontalHelper == null) {
            mHorizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager)
        }
        return mHorizontalHelper
    }
}


Now in your activity-

        //start snap
        val startSnapHelper = StartSnapHelper()
        startSnapHelper.attachToRecyclerView(recyclerView2)



Full Project Code-


activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tvCenterSnap"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="10dp"
        android:text="Center Snap"
        android:layout_marginTop="135dp"
        android:textSize="16sp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintTop_toBottomOf="@id/tvCenterSnap"
        tools:listitem="@layout/rowview_snap" />

    <TextView
        android:id="@+id/tvStartSnap"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:text="Start Snap"
        android:textSize="16sp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/recyclerView1" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintTop_toBottomOf="@id/tvStartSnap"
        tools:listitem="@layout/rowview_snap" />

</androidx.constraintlayout.widget.ConstraintLayout>


rowview_snap.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="260dp"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:minHeight="160dp"
    android:background="@drawable/bg_rowview"
    android:layout_margin="5dp">


    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:text="Item 1"
        android:textSize="22sp"
        android:textColor="@color/white"
        android:textStyle="bold"/>





</androidx.constraintlayout.widget.ConstraintLayout>


bg_rowview.xml in drawable-

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <solid android:color="@color/teal_700" />
    <stroke
        android:width="1dp"
        android:color="#C3636363" />

    <corners android:radius="10dp" />

</shape>


TestAdapter.kt
package com.example.snaphelpersampleapp

import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.rowview_snap.view.*


class TestAdapter(private val list: ArrayList<String>) :
    RecyclerView.Adapter<TestAdapter.ViewHolder>() {

    //this method is returning the view for each item in the list
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val v = LayoutInflater.from(parent.context)
            .inflate(R.layout.rowview_snap, parent, false)
        return ViewHolder(v)
    }

    //this method is binding the data on the list
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bindItems(list[position], position)


    }

    //this method is giving the size of the list
    override fun getItemCount(): Int {
        return list.size
    }

    //the class is hodling the list view
    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

        @SuppressLint("SetTextI18n")
        fun bindItems(item: String, position: Int) {

            itemView.textView.text = "Item $position"

        }
    }

}


MainActivity.kt

package com.example.snaphelpersampleapp

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearSnapHelper
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {
    private val context = this

    private val list1 = ArrayList<String>()

    private val adapter1 = TestAdapter(list1)


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

        recyclerView1.layoutManager =
            LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
        recyclerView1.adapter = adapter1

        recyclerView2.layoutManager =
            LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
        recyclerView2.adapter = adapter1

        //center Snap
        val snapHelper = LinearSnapHelper()
        snapHelper.attachToRecyclerView(recyclerView1)

        //start snap
        val startSnapHelper = StartSnapHelper()
        startSnapHelper.attachToRecyclerView(recyclerView2)


        //set Temp data
        for (x in 0 until 10) {
            list1.add("Item")
        }
        adapter1.notifyDataSetChanged()


    }
}


Others Files-
strings.xml
<resources>
    <string name="app_name">Snap helper sample app</string>
</resources>


themes.xml

<resources xmlns:tools="http://schemas.android.com/tools">
    <!-- Base application theme. -->
    <style name="Theme.SnapHelperSampleApp" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
        <!-- Primary brand color. -->
        <item name="colorPrimary">@color/purple_500</item>
        <item name="colorPrimaryVariant">@color/purple_700</item>
        <item name="colorOnPrimary">@color/white</item>
        <!-- Secondary brand color. -->
        <item name="colorSecondary">@color/teal_200</item>
        <item name="colorSecondaryVariant">@color/teal_700</item>
        <item name="colorOnSecondary">@color/black</item>
        <!-- Status bar color. -->
        <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
        <!-- Customize your theme here. -->
    </style>

    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorAccent">@color/purple_500</item>
        <item name="colorPrimary">@color/purple_500</item>
        <item name="colorPrimaryDark">@color/purple_500</item>
    </style>

</resources>

AndroidManifest.xml   
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.snaphelpersampleapp">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>



See the output in this video-








Please follow me on blog.
Share this article


Thanks














Comments

Popular posts from this blog

How to fetch Latitude, Longitude from address and vice-versa(address from Latitude, Longitude) using Google Geo coder SDK in android| Kotlin

 In this Android development related article, you will get a simple solution that, how to get address using Latitude, Longitude and vice-versa. i.e latitude, longitude from an address text. It is very easy and simple. Read full article and carefully follow all the steps. Here we use google Geocoder SDK. Okay, first we create an android project in kotlin and create an Activity say MainActivity.kt. Use the below code- Function get Latitude, Longitude from Address- fun getLatLngFromAddress (context: Context, mAddress: String): String { val coder = Geocoder(context) lateinit var address: List<Address> try { address = coder.getFromLocationName(mAddress, 5 ) if (address == null ) { return "Fail to find Lat,Lng" } val location = address[ 0 ] return " Latitude: ${location.latitude}\n Longitude: ${location.longitude}" } catch (e: Exception...

onBackPressed() method is deprecated, you are looking for an alternative? Here It is the Latest Solution in android | Kotlin

With the evolution of Android development, several APIs and functions get deprecated over time to make way for more robust and flexible alternatives. One such deprecation that developers need to be aware of is the onBackPressed() method in Android. In Android, onBackPressed() was commonly used to handle back button presses within an activity. However, with the introduction of the Jetpack libraries and the emphasis on more structured navigation, this method has been deprecated. This blog will explore why onBackPressed() is deprecated and what the best alternative solutions are in Kotlin for handling back navigation. Why onBackPressed() is Deprecated The primary reasons for deprecating onBackPressed() include: Improved Navigation Architecture: Android Jetpack's Navigation Component provides a more consistent and predictable way to handle navigation, including back navigation. Lifecycle Awareness: Handling back...

How to consume REST APIs in Laravel | Laravel Development | Solution

In Laravel, you can call a REST API using the HTTP client provided by the framework. Laravel's HTTP client allows you to make GET, POST, PUT, DELETE, and other HTTP requests to external APIs. Here's how you can call a REST API in Laravel: Install Laravel (if not already done): If you haven't already set up a Laravel project, you can create one using Composer by running the following command: composer create - project -- prefer - dist laravel / laravel project - name Create a Controller (optional): You can create a controller to encapsulate the API call logic, but this step is not strictly necessary. You can also make API calls directly from your routes or other parts of your application. To create a controller, run the following command: php artisan make: controller ApiController Make an API Request: You can make API requests using Laravel's HTTP client, which is a fluent, expressive interface for making HTTP requests. Here's how you can make a simple GET request t...