Wearable RecyclerView
Tags: android, wearos
Published: 2020-07-16 06:21:06

>The Wearable UI Library includes the WearableRecyclerView class, which is a RecyclerView implementation for creating lists optimized for wearable devices. You can use this interface in your wearable app by creating a new WearableRecyclerView container.
[![Video of a Wearable Recycler View](http://img.youtube.com/vi/8D_p9JbGZ6I/0.jpg)](https://www.youtube.com/watch?v=8D_p9JbGZ6I&feature=emb_logo)

Wearable recyclerview is used to create a circular layout and is an alternative to Boxlayout on Circular WearOS.
The most used public methods of this view are:
1. setCircularScrollingGestureEnabled(boolean): For enabling/disabling circular touch scrolling for this view.
2. setEdgeItemsCenteringEnabled(boolean): This method is used to indicate if the view should always align the first and last items with the vertical center of the screen.
Below I will give an example with the Home screen of [DCLM Watch](https://play.google.com/store/apps/details?id=org.dclm.live.watch)

First the layout file and then the list item, the Adapter and the Activity
```xml
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.wear.widget.WearableRecyclerView
            android:id="@+id/recycler_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#000"
            android:scrollbars="vertical"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <ImageView
            android:id="@+id/background"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:alpha="0.10"
            android:scaleType="fitXY"
            android:src="@drawable/nlogo"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.0"
            tools:ignore="ContentDescription" />



    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
```

```xml
<?xml version="1.0" encoding="utf-8"?>

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/menu_container"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <import type="androidx.core.content.ContextCompat"/>
        <variable
            name="data"
            type="org.dclm.live.watch.MainScreen" />
    </data>
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/transparent">
        <!--   -->
        <!-- -->

        <ImageView
            android:id="@+id/menu_icon"
            android:layout_width="35dp"
            android:layout_height="35dp"
            android:background="@android:color/transparent"
            android:src="@{ContextCompat.getDrawable(context, data.drawable)}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            tools:ignore="HardcodedText" />

        <TextView
            android:id="@+id/menu_item"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="5dp"
            android:text="@={data.heading}"
            android:textColor="#fff"
            android:textSize="13sp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@+id/menu_icon"
            app:layout_constraintTop_toTopOf="@+id/menu_icon"
            tools:text="swsssswxwx masxsag sxsxbvx" />

        <TextView
            android:id="@+id/menu_sub"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="5dp"
            android:text="@={data.category}"
            android:textColor="#fff"
            android:textSize="12sp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@+id/menu_icon"
            app:layout_constraintTop_toBottomOf="@+id/menu_item"
            tools:text="swsssswxwx " />



    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

```

```kotlin
class MainActivity : WearableActivity() {
    private lateinit var binding: ActivityMainBinding
    private lateinit var adapter:MainAdapter
    private lateinit var mainScreen: MutableList<MainScreen>

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        mainScreen = ArrayList<MainScreen>()
        mainScreen.add(MainScreen(1, R.drawable.nlogo2, getString(R.string.app_radio)))
        mainScreen.add(MainScreen(2, R.drawable.baba, getString(R.string.recent_sermons)))
        adapter = MainAdapter(mainScreen, this)
        binding.recyclerView.isEdgeItemsCenteringEnabled = true
        binding.recyclerView.layoutManager = WearableLinearLayoutManager(this)
        binding.recyclerView.isCircularScrollingGestureEnabled = true;
        binding.recyclerView.isEdgeItemsCenteringEnabled = true
        binding.recyclerView.adapter = adapter

        setAmbientEnabled()
    }

    override fun onExitAmbient() {
        super.onExitAmbient()

       
    }

    override fun onEnterAmbient(ambientDetails: Bundle?) {
        super.onEnterAmbient(ambientDetails)

       
    }
}

data class MainScreen(var id: Int, var image: Int, var name: String)
```

```kotlin
class MainAdapter(val main: MutableList<MainScreen>, val context: Context): RecyclerView.Adapter<MainAdapter.Holder>() {


    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
        val binding = DataBindingUtil.inflate<ListItemBinding>(LayoutInflater.from(context), R.layout.list_item, parent, false)
        return Holder(binding)
    }

      override fun getItemCount() = main.size

    override fun onBindViewHolder(holder: Holder, position: Int) {
        val main1 = main[position]
        holder.binding.data = main1
        holder.binding.root.setOnClickListener {
            context.apply {
                if (main1.id == 1){
                    startActivity(Intent())
                } else{
                    startActivity(Intent())
                }
            }

        }
    }

    class Holder(val binding: ActivityMainListBinding) : RecyclerView.ViewHolder(binding.root) {

    }
}
```
*If you need to implement custom child layout behavior on scroll, then you can use then you use this constructor WearableLinearLayoutManager(Context context, LayoutCallback layoutCallback)and then set your custom Layout Callback as the parameter for the layoutCallback. You can trust Android Magic by coping theirs as your custom LayoutCallback*
```kotlin
/** How much should we scale the icon at most.  */
private const val MAX_ICON_PROGRESS = 0.65f

class CustomScrollingLayoutCallback : WearableLinearLayoutManager.LayoutCallback() {

    private var progressToCenter: Float = 0f

    override fun onLayoutFinished(child: View, parent: RecyclerView) {
        child.apply {
            // Figure out % progress from top to bottom
            val centerOffset = height.toFloat() / 2.0f / parent.height.toFloat()
            val yRelativeToCenterOffset = y / parent.height + centerOffset

            // Normalize for center
            progressToCenter = Math.abs(0.5f - yRelativeToCenterOffset)
            // Adjust to the maximum scale
            progressToCenter = Math.min(progressToCenter, MAX_ICON_PROGRESS)

            scaleX = 1 - progressToCenter
            scaleY = 1 - progressToCenter
        }
    }
}
```