Android scroll to position in Recylerview not working - android-recyclerview

I want to scroll the RecyclerView to a position, and I use LinearLayoutManager.scrollToPositionWithOffset() to scroll.
But it does not work. Could any one help me?

RecyclerView rv = findViewById(R.id.recycler_view);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
rv.setLayoutLayoutManager(layoutManager);
layoutManager.smoothScrollToPosition(position);
Scrolling RecyclerView to certain item position can be achieved with LayoutManager which is used with that particular RecyclerView. Plz refer to above piece of code

If you don't have a lot of items in your list, you can use LinearSmoothScroller
val smoothScroller = object : LinearSmoothScroller(activity) {
override fun getVerticalSnapPreference(): Int {
return SNAP_TO_START
}
}
and then when you want to scroll:
smoothScroller.targetPosition = position // position on which item you want to scroll recycler view
binding.cardsRecycler.layoutManager?.startSmoothScroll(smoothScroller)

Related

Move first and last element of the RecyclerView to the center of the widget

How move the first and the last element of RecyclerView to the center of the widget?
Example
I found next example: RecyclerView allow first/last items to be scrolled to the centre
But i can't describe this solution for my case. There is my code:
class CustomLinearLayoutManager(context: Context): LinearLayoutManager(context , LinearLayoutManager.HORIZONTAL, false) {
override fun getPaddingStart(): Int {
return width / 2
}
override fun getPaddingEnd(): Int {
return paddingStart
}
}
I feel that I have implemented incorrectly this solution
Please let me know how correctly to realize move outermost items to the center in horizontal RecyclerView widget.

How to reference a button from different view in Fragment. Kotlin

I want to achieve a simple task. I have an invisible button in one layout and a have a Fragment. When this function is executed I want the button in the other layout to become visible. However this layout with the button is not in the Fragment layout, which means I have to reference that button in the Fragment, but I don't know how to go about that.
This is what Fragment will look like to first time users. The images you see are in a recyclerview which inflates a layout. That layout has the invisible button.
Fragment class
//item subscribed
if (subscribeValueFromPref) {
subscribeAbstract.visibility = View.GONE
// abstractDownload.visibility = View.VISIBLE
} else {
subscribeAbstract.visibility = View.VISIBLE
// abstractDownload.visibility = View.VISIBLE
}
}
When this line of code executed the button in the fragment is gone and the button from the other layout becomes visible. As you can see I put two strokes in front of that code. Once the code has been executed the layout should look like this.
Summary
I want to reference a button in another layout from a fragment class.
Do you even need to communicate between fragments? Your example looks like a single fragment with a subscribe button, and a RecyclerView that contains items which have a button that can be displayed or hidden. You can just make that part of your Adapter's state, like this:
class MyAdapter : RecyclerView.Adapter<ViewHolder>() {
var showDownloadButtons = false
set(value) {
field = value
// call this to update the display (calls onBindViewHolder for items)
notifyDataSetChanged()
}
override fun onBindViewHolder(viewHolder: ViewHolder, position.Int) {
...
// when displaying an item, show or hide the download button as appropriate
viewHolder.downloadButton.visibility = if (showDownloadButtons) VISIBLE else INVISIBLE
}
}
Then in your fragment, when you work out your UI state based on that subscription value, you can just handle your main button and tell the adapter what to display:
if (subscribeValueFromPref) {
subscribeAbstract.visibility = View.GONE
adapter.showDownloadButtons = true
} else {
subscribeAbstract.visibility = View.VISIBLE
adapter.showDownloadButtons = false
}

offset set with getItemOffsets disappears after scroll

I have a horizontal RecyclerView which works with a FlexLayoutManager. I also have some decorations set with RecyclerView.ItemDecoration.
My getItemOffsets method looks something like this:
override fun getItemOffsets(outRect: Rect, view: View, recyclerView: RecyclerView, state: RecyclerView.State) {
super.getItemOffsets(outRect, view, recyclerView, state)
val position: Int = recyclerView.getChildAdapterPosition(view)
if(position meets some rules){
outRect.top = some values here
}
if(viewType == CERTAIN_VIEW_TYPE){
outRect.bottom = some value
}
}
..onDrawOver(){
//I draw the decorations here
}
This works, the views that I set as decorations are shown and they are at the right position.
The problem that I have is that AFTER I SCROLL TO RIGHT AND THEN BACK TO LEFT, the offset set by outRect.top is set to 0 and my decorations overlap my items.
The curious stuff is that offset set by outRect.bottom doesn't disappear or cause any issues.
I just specify that the offset set by outRect.top is set only for certain positions.
Also my decorations don't disappear, just the margin set initially by outRect.top is not there anymore
Can you please help me with this issue?
Thank you
EDIT:
This can be the result of view recycling I guess, because I see that after scroll other items now have top offset even though I did not intend to set it for them
I had the same problem with item offsets when scrolling.
My case was ->
I had a RecyclerView with a GridLayoutManager, orientation was horizontal and span count set to 2
I've added a custom item decoration to the RecyclerView related to the requirements that I had, by just adding some space around the items and making calculations.
Used the same overridden function as you and set the value to top, bottom, left and right.
Anyway the problem that I had, was at how I was getting the position of the view that I wanted to make my changes.
val viewHolder = recyclerView.findContainingViewHolder(view) ?: return
val adapterPosition = viewHolder.absoluteAdapterPosition
val childPosition = parent.indexOfChild(view)
val isEvenPosition = adapterPosition % 2 == 0
Previously I was using childPosition but when scrolling I was having the problem, when I've used adapterPosition the views were getting the correct amount of space.

RecyclerView custom LayoutManager remove unwanted views

I have a custom LayoutManager (inherited from LinearLayoutManager) that needs to calculate the item width of each child and remove all children from RecyclerView that has no space for them to appear.
Sample code (edited V2):
override fun onLayoutChildren(recycler: RecyclerView.Recycler, state: RecyclerView.State) {
super.onLayoutChildren(recycler, state)
// skip if orientation is vertical, for now we only horizontal custom menu
if (orientation == RecyclerView.VERTICAL) return
// skip if adapter has no items
if (itemCount == 0) return
var totalItemWidth = 0
var totalItemsCanFit = 0
// calculate menu item width and figure out how many items can fit in the screen
for (i in 0 until childCount) {
getChildAt(i)?.let { childView ->
totalItemWidth += getDecoratedMeasuredWidth(childView)
}
if (screenWidth > totalItemWidth) {
totalItemsCanFit++
}
}
// if all items can fit, do nothing and show the whole menu
if (childCount > totalItemsCanFit) {
// remove child views that have no space on screen
for (i in childCount - 1 downTo totalItemsCanFit) {
removeAndRecycleViewAt(i, recycler)
}
}
}
I have 2 questions:
Is the sample code above the correct way to approach this problem?
How can I add a 3-dot icon at the end after seeing that not all items could fit?
EDIT:
To clarify, what I am trying to achieve is a popup menu backed by a RecyclerView. The menu has no item limit, instead it should calculate each item width and remove all items that have no space. Also, add a 3-dot menu item as a more option at the end.
Regarding your first question:
See if addDisappearingView(View child) could help you,
according to the documentation:
To be called only during onLayoutChildren(Recycler, State) to add a
view to the layout that is known to be going away, either because it
has been removed or because it is actually not in the visible portion
of the container but is being laid out in order to inform RecyclerView
in how to animate the item out of view.
As for the second question - you simply need to implement a 'load more' feature to your recyclerView. How you'll implement this is up to your needs/design (if you want a button or auto-scroll...).
There are many tutorials for that, for example: https://androidride.com/android-recyclerview-load-more-on-scroll-example/ .

can't recognize onItemClickListener in vertical and horizontal listview adapter

I made vertical listview that contains horizontal listview in each row and I want to implement the event that when I clicked one item, I can add new item at the end of the row.
For that I try to manage the item by ArrayList> and I added setOnItemClickListener in the getView method of vertical adapter. and It doesn't work! Actually It rarely works... (when I clicked about 20 times, It works once.)
I tried unclickable and unfocusable properties in xml layout but doesn't work.
please hlp me... Here is my code
in MainActivity
I used VerticalAdapter like this. I set totallist as the parameter of VerticalAdpater
verListAdapter = new VerticalAdapter(getActivity(), R.layout.schedule_routine, TotalList);
listview.setAdapter(verListAdapter);
public View getView(int position, View convertView, ViewGroup parent) {
View rowView;
this.aposition = position;
rowView = LayoutInflater.from(getContext()).inflate(R.layout.part_list_item, null);
hListView = (HorizontialListView) rowView.findViewById(R.id.hlistview);
tv_info = (TextView) rowView.findViewById(R.id.tv_infoitem);
tv_info.setText(Integer.toString(position));
hListView.setOnItemClickListener(new OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> parent, View view, int iposition, long id) {
tv_info.setText("hello");
PartContent temp_part = new PartContent("part", R.drawable.plus);
PartContent temp_base_part = new PartContent("part", R.drawable.dumb);
if(iposition == (totallist.get(aposition).size()) - 1) {
tv_info.setText(Integer.toString(iposition));
totallist.get(aposition).set(iposition, temp_base_part);
totallist.get(aposition).add(temp_part);
}
HorizontialAdapter hortempAdapter = new HorizontialAdapter(getContext(), R.layout.part_item, getItem(iposition));
hListView.setAdapter(hortempAdapter);
hortempAdapter.notifyDataSetChanged();
}});
HorizontialAdapter horListAdapter = new HorizontialAdapter(getContext(), R.layout.part_item, totallist.get(position));
hListView.setAdapter(horListAdapter);
return rowView;
}