An OnScrollListener can be added to a RecyclerView to receive messages when a scrolling event has occurred on that RecyclerView.
When the recycler views vertically scrolls, then the selected item to be centered or on the Top First item, and then the item is automatically centered or to be the first when the item to be selected is set.
RecyclerView
list, in which I want the currently selected item to be shown at the top of the RecyclerView
. I still, however, want the entire list to be scrollable, therefore, removing views from above the selected item is not a possible solution.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:visibility="visible"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/constraint_multiple_options" android:layout_width="match_parent" android:layout_height="0dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> <com.google.android.material.tabs.TabLayout android:id="@+id/tabs" style="@style/MyCustomTabLayout" android:layout_width="0dp" android:layout_height="60.4dp" android:layout_marginTop="10dp" android:elevation="5dp" android:gravity="start" android:tabStripEnabled="false" android:textAlignment="viewStart" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:tabGravity="fill" app:tabIndicatorColor="@android:color/transparent" app:tabIndicatorHeight="0dp" app:tabMode="scrollable" app:tabTextAppearance="@style/MyCustomTextAppearance" /> <androidx.recyclerview.widget.RecyclerView android:id="@+id/linear_recycler_menuItem" android:layout_width="match_parent" android:layout_height="0dp" android:layout_marginTop="12dp" android:orientation="vertical" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/tabs" /> </androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout> <LinearLayout android:id="@+id/mTransparent" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/transparent_color" android:orientation="vertical" android:visibility="gone" /> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_alignParentBottom="true" android:layout_marginTop="50dp" android:background="@android:color/transparent" android:orientation="vertical" android:paddingTop="50dp"> <androidx.cardview.widget.CardView android:id="@+id/card_menu_list" android:layout_width="252dp" android:layout_height="wrap_content" android:layout_above="@id/linear_menubtn" android:layout_alignParentEnd="true" android:layout_alignParentRight="true" android:layout_marginEnd="19dp" android:layout_marginRight="19dp" android:layout_marginBottom="@dimen/margin_20" android:elevation="10dp" android:visibility="gone" app:cardBackgroundColor="@color/white" app:cardCornerRadius="10dp"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/menuListing" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginHorizontal="20dp" android:layout_marginTop="15dp" android:layout_marginBottom="15dp" android:gravity="start" android:textAlignment="viewStart" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.cardview.widget.CardView> <LinearLayout android:id="@+id/linear_menubtn" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:orientation="vertical"> <Button android:id="@+id/menu_btn" android:layout_width="105.6dp" android:layout_height="45.9dp" android:layout_alignParentEnd="true" android:layout_alignParentRight="true" android:layout_gravity="end" android:layout_marginEnd="18dp" android:layout_marginRight="18dp" android:layout_marginBottom="18dp" android:background="@drawable/rounded_all_side_pink" android:padding="10dp" android:text="Menu" android:textColor="@color/white" /> </LinearLayout> </RelativeLayout> </RelativeLayout> </RelativeLayout> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<style name="MyCustomTabLayout" parent="Widget.Design.TabLayout"> <item name="tabIndicatorHeight">0dp</item> <item name="tabPaddingStart">20dp</item> <item name="tabPaddingEnd">20dp</item> <!-- <item name="tabBackground">@drawable/tab_color_selector</item>--> <item name="tabTextAppearance">@style/MyCustomTextAppearance</item> <item name="tabSelectedTextColor">@color/white</item> </style> <style name="MyCustomTextAppearance" parent="TextAppearance.Design.Tab"> <item name="textAllCaps">false</item> <item name="android:textSize">16sp</item> <item name="android:color">@color/black</item> <item name="singleLine">true</item> <item name="android:textColor">@color/black</item> </style> |
1 2 3 4 5 |
<color name="drawer_bg">#FEF8FB</color> <color name="white">#FFFFFF</color> <color name="black">#000000</color> <color name="transparent_color">#66000000</color> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" > <!-- we define background color --> <solid android:color="@color/colorPrimary" /> <!-- we define border color and thick --> <stroke android:width="2dp" android:color="@color/colorPrimary" /> <!-- we define corner radius, note that radius can be different for each corner --> <corners android:radius="10dp" /> </shape> |
Callback method to be invoked when the RecyclerView has been scrolled. This will be called after the scroll has completed.
This callback will also be called if the visible item range changes after a layout calculation. In that case, dx and dy will be 0.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
class RecyclerListingActivity : AppCompatActivity() { private var responseItemList: MutableList<String>? = ArrayList() private var linearLayoutManager: LinearLayoutManager? = null private var menuListAdapter: MenuListAdapter? = null private var dailyCakeListScrollAdapter: DailyCakeListScrollAdapter? = null private var flagCheck = false private var checkCallBack = false private var checkScroll = true private var posSelected = 0 private var totalCount = 0 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_recycler_listing) setData() } private fun setData() { responseItemList?.add("test1") responseItemList?.add("test2") responseItemList?.add("test3") responseItemList?.add("test4") responseItemList?.add("test5") responseItemList?.add("test6") responseItemList?.add("test7") responseItemList?.add("test8") responseItemList?.add("test9") responseItemList?.add("test10") responseItemList?.add("test11") responseItemList?.add("test12") responseItemList?.add("test13") responseItemList?.add("test14") responseItemList?.add("test15") responseItemList?.add("test16") responseItemList?.add("test17") responseItemList?.add("test18") responseItemList?.add("test19") responseItemList?.add("test20") linearLayoutManager = LinearLayoutManager(this@RecyclerListingActivity, LinearLayoutManager.VERTICAL, false) linear_recycler_menuItem.layoutManager = linearLayoutManager menuListing.layoutManager = LinearLayoutManager( this@RecyclerListingActivity, LinearLayoutManager.VERTICAL, false ) setTabs() } private fun setTabs() { for (aq in responseItemList!!.indices) { tabs!!.addTab(tabs!!.newTab().setText(responseItemList!![aq])) tabs!!.tabGravity = TabLayout.GRAVITY_FILL } setAdapter() } private fun setAdapter() { setMenuAdapter() initCategoryMenu() } fun bindWidgetsWithAnEvent() { tabs!!.addOnTabSelectedListener(object : OnTabSelectedListener { override fun onTabSelected(tab: TabLayout.Tab) { checkCallBack = true posSelected = tab.position linear_recycler_menuItem!!.smoothScrollToPosition(tab.position) tabs!!.setSelectedTabIndicatorHeight((2 * resources.displayMetrics.density).toInt()) selectionBackground(posSelected) if (tab.position == totalCount - 1) { checkCallBack = false } } override fun onTabUnselected(tab: TabLayout.Tab) { checkCallBack = false } override fun onTabReselected(tab: TabLayout.Tab) { checkCallBack = true posSelected = tab.position selectionBackground(posSelected) linear_recycler_menuItem!!.smoothScrollToPosition(tab.position) tabs!!.setSelectedTabIndicatorHeight((2 * resources.displayMetrics.density).toInt()) selectionBackground(posSelected) if (tab.position == totalCount - 1) { checkCallBack = false } } }) } private fun initCategoryMenu() { dailyCakeListScrollAdapter = DailyCakeListScrollAdapter(responseItemList!!) linear_recycler_menuItem!!.adapter = dailyCakeListScrollAdapter setScrollListener() bindWidgetsWithAnEvent() } private fun setScrollListener() { checkScroll = true linear_recycler_menuItem!!.addOnScrollListener(object : RecyclerView.OnScrollListener() { override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { super.onScrollStateChanged(recyclerView, newState) val visiblePosition = linearLayoutManager!!.findFirstVisibleItemPosition() val firstCompletelyVisiblePosition = linearLayoutManager!!.findFirstCompletelyVisibleItemPosition() totalCount = linearLayoutManager!!.itemCount checkScroll = false if (visiblePosition > -1) { if (!checkCallBack) { if (firstCompletelyVisiblePosition == -1) { selectionBackground(visiblePosition) tabs!!.setScrollPosition(visiblePosition, 0f, true) } else { selectionBackground(firstCompletelyVisiblePosition) tabs!!.setScrollPosition(firstCompletelyVisiblePosition, 0f, true) } } else { selectionBackground(posSelected) tabs!!.setScrollPosition(posSelected, 0f, true) if (firstCompletelyVisiblePosition == posSelected) { checkCallBack = false } } } } }) } private fun selectionBackground(position: Int) { for (i in responseItemList!!.indices) { if (i == position) { val tabLayout = (tabs!!.getChildAt(0) as ViewGroup).getChildAt(position) as LinearLayout val tabTextView = tabLayout.getChildAt(1) as TextView if (tabTextView != null) { tabTextView.setTextColor(Color.parseColor("#ffffff")) tabTextView.setPadding(11, 7, 11, 7) tabTextView.setBackgroundResource(R.drawable.rounded_all_side_pink) } val tab = (tabs!!.getChildAt(0) as ViewGroup).getChildAt(position) val p = tab.layoutParams as MarginLayoutParams p.setMargins(0, 0, 0, 0) tab.requestLayout() tabs!!.isSmoothScrollingEnabled = true tabs!!.setScrollPosition(position, 0f, true) } else { val tabLayout = (tabs!!.getChildAt(0) as ViewGroup).getChildAt(i) as LinearLayout val tabTextView = tabLayout.getChildAt(1) as TextView if (tabTextView != null) { tabTextView.setPadding(11, 7, 11, 7) tabTextView.setTextColor(Color.parseColor("#000000")) tabTextView.setBackgroundResource(R.drawable.rounded_all_side_transparent) } val tab = (tabs!!.getChildAt(0) as ViewGroup).getChildAt(i) val p = tab.layoutParams as MarginLayoutParams p.setMargins(0, 0, 0, 0) tab.requestLayout() } } } private fun setMenuAdapter() { menuListAdapter = MenuListAdapter( responseItemList!!, object : MenuListAdapter.OnItemClickListener { override fun onItemClick(position: Int, check: Boolean) { checkCallBack = check posSelected = position mTransparent!!.visibility = View.GONE card_menu_list!!.visibility = View.GONE flagCheck = false tabs!!.isSmoothScrollingEnabled = true selectionBackground(position) tabs!!.setScrollPosition(position, 0f, true) linear_recycler_menuItem!!.smoothScrollToPosition(position) } }) menuListing!!.adapter = menuListAdapter menu_btn!!.setOnClickListener { if (!flagCheck) { checkCallBack = false mTransparent!!.visibility = View.VISIBLE card_menu_list!!.visibility = View.VISIBLE flagCheck = true } else { checkCallBack = false mTransparent!!.visibility = View.GONE card_menu_list!!.visibility = View.GONE flagCheck = false } } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class DailyCakeListScrollAdapter( var categoryMenuItemList1: List<String> ) : RecyclerView.Adapter<FirstViewHolderr>() { override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): FirstViewHolderr { val v = LayoutInflater.from(viewGroup.context) .inflate(R.layout.layout_menu_list, viewGroup, false) return FirstViewHolderr(v) } override fun onBindViewHolder(firstViewHolder: FirstViewHolderr, i: Int) { firstViewHolder.itemView.text_cake.text = categoryMenuItemList1[i] firstViewHolder.itemView.textCount.text = "Pizza " + i + 1 } override fun getItemCount(): Int { return categoryMenuItemList1.size } inner class FirstViewHolderr(itemView: View) : RecyclerView.ViewHolder(itemView) } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
<?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" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginHorizontal="3dp" android:layout_marginBottom="10dp"> <androidx.cardview.widget.CardView android:id="@+id/card_image" android:layout_width="105sp" android:layout_height="105sp" app:cardCornerRadius="10dp" android:layout_margin="3dp" app:cardElevation="5dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/image_cake" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="start" android:scaleType="centerCrop" android:src="@drawable/ic_launcher_background" android:textAlignment="viewStart" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> </androidx.cardview.widget.CardView> <TextView android:id="@+id/text_cake" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="7.8dp" android:layout_marginLeft="7.8dp" android:layout_marginTop="5dp" android:gravity="start" android:text="Pizza Hut" android:textAlignment="viewStart" android:textColor="@color/black" android:textSize="17sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/card_image" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/textCount" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="7.8dp" android:layout_marginEnd="14dp" android:layout_marginTop="4dp" android:paddingBottom="5dp" android:gravity="start" android:minLines="2" android:maxLines="4" android:text="Pizza" android:textAlignment="viewStart" android:textColor="@color/black" android:textSize="14sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/card_image" app:layout_constraintTop_toBottomOf="@id/text_cake" app:layout_constraintVertical_bias="0.0" android:layout_marginLeft="7.8dp" android:layout_marginRight="14dp" /> <TextView android:id="@+id/text_cakePrice" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="6dp" android:layout_marginVertical="8dp" android:layout_marginEnd="14dp" android:gravity="start" android:textAlignment="viewStart" android:textColor="@color/black" android:text="20.00" android:textSize="15sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@id/textCount" android:layout_marginLeft="6dp" android:layout_marginRight="14dp" /> <TextView android:id="@+id/text_cakeOfferPrice" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="6dp" android:layout_marginVertical="8dp" android:layout_marginEnd="14dp" android:gravity="start" android:text="price" android:textAlignment="viewStart" android:textColor="@color/black" android:textSize="15sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@id/text_cakePrice" app:layout_constraintTop_toBottomOf="@id/textCount" android:layout_marginLeft="6dp" android:layout_marginRight="14dp" /> </androidx.constraintlayout.widget.ConstraintLayout> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
class MenuListAdapter( private val categoryMenuItemList: List<String>, private val listener: OnItemClickListener ) : RecyclerView.Adapter<MenuListAdapter.ViewHolder>() { var flag = false var positionSelected = 0 interface OnItemClickListener { fun onItemClick(position: Int, check: Boolean) } override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): ViewHolder { val v = LayoutInflater.from(viewGroup.context).inflate(R.layout.item_menu, viewGroup, false) return ViewHolder(v) } override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) { viewHolder.itemView.menu_name.text = categoryMenuItemList[position] flag = if (positionSelected == position) { viewHolder.itemView.menu_name.setTextColor(Color.parseColor("#D1007E")) viewHolder.itemView.text_menu_counts.setTextColor(Color.parseColor("#D1007E")) false } else { viewHolder.itemView.menu_name.setTextColor(Color.parseColor("#000000")) viewHolder.itemView.text_menu_counts.setTextColor(Color.parseColor("#000000")) true } } override fun getItemCount(): Int { return categoryMenuItemList.size } inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { init { itemView.setOnClickListener { positionSelected = adapterPosition notifyDataSetChanged() listener.onItemClick(positionSelected, true) } } } } |
You can refer to this screenshot for the menu list view in the application. How it looks like
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingBottom="20dp" xmlns:app="http://schemas.android.com/apk/res-auto"> <TextView android:id="@+id/menu_name" android:layout_width="0dp" android:layout_height="wrap_content" android:gravity="start" android:textAlignment="viewStart" android:text="" android:textColor="@color/black" android:textSize="17sp" app:layout_constraintEnd_toStartOf="@id/text_menu_counts" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/text_menu_counts" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="start" android:text="" android:textColor="@color/black" android:textAlignment="viewStart" android:textSize="17sp" android:focusable="false" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toEndOf="@id/menu_name" app:layout_constraintTop_toTopOf="@id/menu_name" app:layout_constraintBottom_toBottomOf="@id/menu_name"/> </androidx.constraintlayout.widget.ConstraintLayout> |
Finally, we implemented the code part of the scrolling view Recycler in this blog.
Also, we use the base class for smooth scrolling. Handles basic tracking of the target view position and provides methods to trigger a programmatic scroll.
An instance of SmoothScroller is only intended to be used once. You should create a new instance for each call to LayoutManager#startSmoothScroll(SmoothScroller)
https://mobikul.com/adding-fast-scroller-recyclerview/
Another mentioned URL
Be the first to comment.