DEV Community

Cover image for Wearable RecyclerView
Ochornma Promise
Ochornma Promise

Posted on

Wearable RecyclerView

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

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

First the layout file and then the list item, the Adapter and the Activity

<?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>
Enter fullscreen mode Exit fullscreen mode
<?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>

Enter fullscreen mode Exit fullscreen mode
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)
Enter fullscreen mode Exit fullscreen mode
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) {

    }
}
Enter fullscreen mode Exit fullscreen mode

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

/** 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
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
prasan29 profile image
Prasanna

That's a good read, buddy!