I have a ViewPager implemented without fragment (just view). Each page contains a list of elements, but the list hasn't always the same size.
I tried to set the ViewPager dimension with this code (extends ViewPager so I can override this function) :
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = 0;
for(int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int h = child.getMeasuredHeight();
if(h > height) height = h;
}
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
The problem is that it set the same height for every page. I need a custom height for each page, depending of the height of the list.
I also tried to use setOnPageChangeListener calling requestLayout() and invalidate() on the ViewPager, but the size remains the same. Maybe I did it wrong...
Here is some code that might be useful :
A part of my PagerAdapter:
#Override
public Object instantiateItem(ViewGroup container, int position) {
// Inflate a new layout from our resources
View view = getActivity().getLayoutInflater().inflate(R.layout.fragment_home_pager,
container, false);
mContainerView = (ViewGroup) view.findViewById(R.id.news_container);
reloadNews(position);
// Add the newly created View to the ViewPager
container.addView(view);
// Return the View
return view;
}
A part of my XML layout:
<ScrollView
android:id="#+id/news_scrollview"
android:layout_width="match_parent"
android:layout_height="fill_parent">
<com.ViewPagerWithHeight
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white"/>
</ScrollView>
Thanks of lot for helping me,
The ViewPager height cannot vary per-page as you are hoping. You could attempt to subclass ViewPager to add this ability, but handling the visual transitions between differently-sized pages is going to be very fiddly. Another alternative may be to re-measure the ViewPager on every page change (but I would expect the transition to look pretty bad). You would need to set a page change listener, then call requestLayout on the ViewPager. Your ViewPager onMeasure would need to find the height of the currently-visible child only, and set the ViewPager height to match this.
Aside: I don't see you calling setMeasuredDimension anywhere. When measuring a view, you must call this method with your calculated width and height to inform the view what size it has been measured at. Currently you are calling through to super.onMeasure at the end of your custom onMeasure which, while valid, means the ViewPager will always be measured with the "default" width and height. In this case, that happens to match the height of the largest page anyway.
See the docs for onMeasure for more details. In particular:
CONTRACT: When overriding this method, you must call setMeasuredDimension(int, int) to store the measured width and height of this view. Failure to do so will trigger an IllegalStateException, thrown by measure(int, int). Calling the superclass' onMeasure(int, int) is a valid use.
I just find out something that do the job.
I moved the Scrollview inside the pageItem.xml so I can set the page size (for all pages) but still can scroll if the list is long enough. The ViewPager is now inside a FrameLayout with layout_height = fill_parent.
The page size is fixed, but the scrollview do the trick...
The ViewPager (inside my fragment) :
<FrameLayout
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:id="#+id/viewpagercontainer">
<com.ViewPagerWithHeight
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white"/>
</FrameLayout>
The "Page item" :
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/news_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:showDividers="middle"
android:divider="?android:dividerHorizontal" />
</ScrollView>
onMeasure function:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(containerHeight, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
How to set the attribute containerHeight (more info here):
final View pagerContainer = (View) mView.findViewById(R.id.viewpagercontainer);
pagerContainer.post(new Runnable() {
#Override
public void run() {
mViewPager.setContainerHeight(pagerContainer.getMeasuredHeight());
}
});
Related
I wanted to show the part of next and previous items of the recyclerview as compared to the currently visible item (as in this third party library). However I managed to do so with my native recyclerview.
That's sound great to me, now I want to set the height of my currently visible item larger than the next and previous items to it as shown in the gif of the above mentioned library!
I have managed to show the next and previous items with my code as in the following stages:
1. Setting the recyclerview adapter as:
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
locationTypeFragmentBinding.mRecylerview.setLayoutManager(layoutManager);
locationTypeFragmentBinding.mRecylerview.setHasFixedSize(true);
final LocationTypePictureAdapter locationTypePictureAdapter =
new LocationTypePictureAdapter(getActivity(), locationDetails,false);
final SnapHelper snapHelper = new PagerSnapHelper();
snapHelper.attachToRecyclerView(locationTypeFragmentBinding.mRecylerview);
locationTypeFragmentBinding.mRecylerview.post(new Runnable() {
#Override
public void run() {
locationTypeFragmentBinding.mRecylerview.
setAdapter(locationTypePictureAdapter);
}
});
2. My RecyclerView in the xml is:
<android.support.v7.widget.RecyclerView
android:id="#+id/mRecylerview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/buttonsHolder"
android:clipToPadding="false"
android:orientation="horizontal"
android:padding="#dimen/_10sdp"
android:paddingStart="#dimen/_15sdp"
android:paddingEnd="#dimen/_15sdp"
android:scrollbarStyle="outsideOverlay"
android:visibility="gone"/>
3. My RecyclerView item xml is:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mainContainer"
android:layout_width="match_parent"
android:layout_height="#dimen/_200sdp">
<android.support.v7.widget.CardView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="#dimen/_5sdp"
android:layout_marginEnd="#dimen/_5sdp"
android:background="#android:color/transparent"
app:cardElevation="0dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/locationPicture"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
</android.support.v7.widget.CardView>
</RelativeLayout>
4. What I need to achieve is like:
I know I can use the above mentioned library, but I want to set the height of the currently visible item larger than the next and previous items of my recyclerview which are to be shown to the user.
Can somebody please figure out what I am doing wrong with my code?
Example Image of what I need
See Here
I am not familiar the library that you are using but You can also use CarouselLayoutManager to achieve this look, with this library you will have one elevated item that will be above all others and this will look bigger than the rest of the items.
How to use:
In your gradle:
implementation 'com.azoft.carousellayoutmanager:carousel:version'
When declaring an adapter:
final CarouselLayoutManager layoutManager = new CarouselLayoutManager(CarouselLayoutManager.VERTICAL);
final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
Edit:
If you want to do it natively you can do something like this:
Create recyclerView:
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fadingEdge="horizontal"
android:overScrollMode="never"
android:requiresFadingEdge="horizontal" />
Attach your recyclerView to SnapHelper like this:
LinearSnapHelper snapHelper = new LinearSnapHelper();
snapHelper.attachToRecyclerView(recyclerView);
Now you need to provide the logic for your currently centered item:
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
float position = (float) recyclerView.computeHorizontalScrollOffset() / (float) itemHeight;
int itemPosition = (int) Math.floor(position);
}
super.onScrollStateChanged(recyclerView, newState);
}
});
I had added animation to items of a recycleView using the below method. I hope it may solve your problem if you are able to do something similar to this
Try this changes in your onBindViewHolder of your recycleView adapter.
#Override
public void onBindViewHolder(#NonNull final CustomViewHolder holder, int position)
{
// do your work
setAnimation(holder.itemView, position);
}
and in setAnimation which receives the view and its position
void setAnimation(View view, int position) {
//this allows new views coming in the recycle view to slide to left while scrolling down and slide to right while scrolling up.
if (lastPosition < position) {
Animation animation = AnimationUtils.loadAnimation(context, android.R.anim.slide_in_left);
view.startAnimation(animation);
} else {
Animation animation = AnimationUtils.loadAnimation(context, R.anim.slide_in_right);
view.startAnimation(animation);
}
lastPosition = position;
}
Similarly, if you know the position or location of view which is in middle, you can use your anim to zoom it up or zoom down other views in the recycleView.
If you cary about performance it is the best to do all animations things in Layout Manager. Tamir Abutbul gives you very good solution, why you want to reinvent the wheel? Without library there is ready layout manager you need : https://stackoverflow.com/a/41307581/2551094
I am trying to build a custom view but there seems to be something that I am not getting.
I have overriden the onSizeChanged and onDraw methods and added my custom view in the activity layout and given it a height of say 100dp and pinned it to the bottom and start and end of the parent relative layout.
However the view doesn't render correctly and there is a blank empty space beneath it.
below is my onDraw and onSizedChanged methods
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
viewHeight = h;
viewWidth = w;
}
#Override
protected void onDraw(Canvas canvas) {
// draw background
painter.setStrokeWidth(viewHeight);
painter.setColor(Color.BLUE);
canvas.drawLine(0, 0, viewWidth, 0, painter);
}
below is how I am adding the view to the layout xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/activity_registration"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="com.example.activities.RegistrationActivity">
<com.example.custom.widgets.MyCustomView
android:id="#+id/holder"
android:layout_alignParentEnd="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="100dp"/>
<FrameLayout
android:layout_above="#+id/holder"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:text="kjdgfjkasdgfjkahsdgfjkhsa"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
</RelativeLayout>
this is how it looks
FWIW, I also trying embedding my custom view inside a FrameLayout and explicitly setting the height of the FrameLayout and setting the height of my custom view to match_parent. still no success.
Overriding onMeasure() in your custom view class will set the size of your view dependent on the layout constraints provided by the parent.
This should give your custom view a height of 100dp:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = Math.min(100, MeasureSpec.getSize(heightMeasureSpec));
setMeasuredDimension(width, height);
}
If you change the parent's constraints, you will need to change the MeasureSpec values that are passed into the method. See this question: https://stackoverflow.com/a/12267248/7395923
Change the onDraw() method to this:
protected void onDraw(Canvas canvas) {
// draw background
painter.setStrokeWidth(getWidth());
painter.setColor(Color.BLUE);
canvas.drawLine(0, 0, getWidth(), 0, painter);
}
And remove the onSizeChanged() method.
I'm adding views programatically into FrameLayout:
public class PixelGridView extends FrameLayout {
...
public void addViewWithoutCoords(TableView view, int column, int row) {
float x = column * mCellSideSize;
float y = row * mCellSideSize;
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
view.setLayoutParams(lp);
view.setLeft(0);
view.setTop(0);
view.setX(x);
view.setY(y);
view.setVisibility(VISIBLE);
addView(view);
}
...
}
However, all they are somehow invisible. getChildCount() returns count with all of them. getVisibility() for each added view also returns VISIBLE.
I can drag'n'drop such views from another ViewGroup into my Framelayout and when I do this, all earlier added views become visible.
view layout file:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<ImageView
android:id="#+id/ivTable"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"/>
<EditText
android:id="#+id/ivTableName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="#color/style_table_grey"
android:textColor="#android:color/white"/>
</RelativeLayout>
Even If I add new view without drag everything become visible.
The item view of the FrameLayout and RelativeLayout can be overlapping. If two item views are in the same positions of FrameLayout, the first loaded item will be covered by the later item.
Try turn on the show layout bounds in developer option of your android devices,and find the position of your item.
I have an Android Layout like this :
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/main_layout"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="#+id/rv_weighing"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="#+id/cv_price_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- another view elements here -->
</android.support.v7.widget.CardView>
</LinearLayout>
Basically I want the first element fill the remaining space between parent and the second element. It works fine until I change the Y position of the second element at runtime. I tried to call .invalidate() and .requestLayout() on both parent and the first element but it seems like doesn't work as expected.
I also tried to change the parent layout using <RelativeLayout> and set android:layout_above="#+id/cv_price_holder" on the first element but didn't work as well.
EDIT : Here is the method that invoked to toggle the layout :
public void togglePriceHolder(){
float newY = mPriceHolderToggleState ? -mPriceHolderToggleLimitY : mPriceHolderToggleLimitY;
int newIcon = mPriceHolderToggleState ? R.drawable.ic_keyboard_arrow_down_white_36dp : R.drawable.ic_keyboard_arrow_up_white_36dp;
mBtnTogglePriceHolder.setImageResource(newIcon);
mCvPriceHolder.animate().translationYBy(newY).setListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {}
#Override
public void onAnimationEnd(Animator animation) {
// refresh the layout
rvWeighing.forceLayout();
mMainLayout.requestLayout();
}
#Override
public void onAnimationCancel(Animator animation) {}
#Override
public void onAnimationRepeat(Animator animation) {}
});
mPriceHolderToggleState = !mPriceHolderToggleState;
}
The question is how can I refresh the layout so the first element can adjust its height when Y position of the second element change ?
Thanks in advance
Try calling forceLayout() on the views whose dimensions might change and then calling requestLayout().
When requestLayout() is called on a view, all the parents of that view are redrawn, but the siblings are not, calling forceLayout() on a particular view, marks that view for the next layout pass(along with the default traversal).
In your particular case, try calling forceLayout() on the siblings you want to redraw, and then call requestLayout() from one of the views.
I'm developing on Amazon Fire TV.
Because it's a TV app(No touch), I need focusables inside row's layout to be able to navigate around.
I have a really simple Recyclerview with image, text, and a focusable. When I press up or down, it all scrolls and stuff correctly, but I noticed that when I navigate faster than scroll can keep up, it creates new viewholders (Off screen) and lags up the UI.
I have created an activity with Creation numbers on it. When I scroll slowly, the highest creation # is 10. But when I scroll fast, I get cards with creation number 60 in a second. This causes an enormous lag and the application drops a lot of frames. Is my approach totally wrong?
Use the code below to test this out.
/**
* Created by sylversphere on 15-04-15.
*/
public class LandfillActivity extends Activity{
private Context context;
private static int ticketNumber;
private static int getTicket(){
ticketNumber ++;
return ticketNumber;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = this;
setContentView(R.layout.landfill_activity);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
GridLayoutManager glm = new GridLayoutManager(context, 2);
recyclerView.setLayoutManager(glm);
SickAdapter sickAdapter = new SickAdapter();
recyclerView.setAdapter(sickAdapter);
}
public class SickViewHolder extends RecyclerView.ViewHolder{
TextView ticketDisplayer;
public ImageView imageView;
public SickViewHolder(View itemView) {
super(itemView);
ticketDisplayer = (TextView) itemView.findViewById(R.id.ticketDisplayer);
imageView = (ImageView) itemView.findViewById(R.id.imageView);
itemView.findViewById(R.id.focus_glass).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
context.startActivity(new Intent(context, LouisVuittonActivity.class));
}
});
}
public void setTicket(int value){
ticketDisplayer.setText(""+value);
}
}
public class SickAdapter extends RecyclerView.Adapter<SickViewHolder>{
#Override
public SickViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
SickViewHolder svh = new SickViewHolder(getLayoutInflater().inflate(R.layout.one_row_element, null));
svh.setTicket(getTicket());
return svh;
}
#Override
public void onBindViewHolder(SickViewHolder holder, int position) {
String[] image_url_array = getResources().getStringArray(R.array.test_image_urls);
Picasso.with(context).load(image_url_array[position % image_url_array.length] ).fit().centerCrop().into(holder.imageView);
}
#Override
public int getItemCount() {
return 100000;
}
}
}
one_row_element.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="200dp"
android:orientation="horizontal">
<ImageView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:src="#mipmap/sick_view_row_bg" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left|center_vertical"
android:layout_marginLeft="15dp"
android:orientation="horizontal">
<TextView
android:id="#+id/virusTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Creation #"
android:textColor="#fff"
android:textSize="40sp" />
<TextView
android:id="#+id/ticketDisplayer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1"
android:textColor="#fff"
android:textSize="40sp" />
</LinearLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/focus_glass"
android:background="#drawable/subtle_focus_glass"
android:focusable="true"
android:focusableInTouchMode="true"/>
</FrameLayout>
</FrameLayout>
test_image_urls.xml (Urls not owned by me)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="test_image_urls"
formatted="false">
<item>http://farm4.static.flickr.com/3175/2737866473_7958dc8760.jpg</item>
<item>http://farm4.static.flickr.com/3276/2875184020_9944005d0d.jpg</item>
<item>http://farm3.static.flickr.com/2531/4094333885_e8462a8338.jpg</item>
<item>http://farm4.static.flickr.com/3289/2809605169_8efe2b8f27.jpg</item>
<item>http://2.bp.blogspot.com/_SrRTF97Kbfo/SUqT9y-qTVI/AAAAAAAABmg/saRXhruwS6M/s400/bARADEI.jpg</item>
<item>http://fortunaweb.com.ar/wp-content/uploads/2009/10/Caroline-Atkinson-FMI.jpg</item>
<item>http://farm4.static.flickr.com/3488/4051378654_238ca94313.jpg</item>
<item>http://farm4.static.flickr.com/3368/3198142470_6eb0be5f32.jpg</item>
<item>http://www.powercai.net/Photo/UploadPhotos/200503/20050307172201492.jpg</item>
<item>http://www.web07.cn/uploads/Photo/c101122/12Z3Y54RZ-22027.jpg</item>
<item>http://www.mitravel.com.tw/html/asia/2011/Palau-4/index_clip_image002_0000.jpg</item>
<item>http://news.xinhuanet.com/mil/2007-05/19/xinsrc_36205041914150623191153.jpg</item>
<item>http://ib.berkeley.edu/labs/koehl/images/hannah.jpg</item>
<item>http://down.tutu001.com/d/file/20110307/ef7937c2b70bfc2da539eea9df_560.jpg</item>
<item>http://farm3.static.flickr.com/2278/2300491905_5272f77e56.jpg</item>
<item>http://www.pic35.com/uploads/allimg/100526/1-100526224U1.jpg</item>
<item>http://img.99118.com/Big2/1024768/20101211/1700013.jpg</item>
<item>http://farm1.static.flickr.com/45/139488995_bd06578562.jpg</item>
</string-array>
</resources>
subtle_focus
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true" android:drawable="#color/glass_focus"/>
<item android:drawable="#color/glass_normal"/>
</selector>
glass_normal is #9000
glass_focus is #0000
Try increasing the maximum number of recycled views in the pool:
recyclerView.getRecycledViewPool().setMaxRecycledViews(50);
50 is an arbitrary number, you can try higher or lower and see what happens.
RecyclerView tries to avoid re-using views that have transient state, so if views are invalidated quickly or are animating, they may not be re-used right away.
Similarly if you have many smaller views, you may end up with more on screen than the default pool size can handle (more common with grid like layouts).
Picasso is holding you up but the suggested solution to build your own mechanism is not the way to go.
Picasso has fallen behind in the last year or so and today there are far better alternatives in the form of Google Glide and Facebook Fresco which specifically released updates to work better with RecyclerView and have proved faster and more efficient in loading, caching and storing in many tests which are available online such as:
http://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/en
https://code.facebook.com/posts/366199913563917/introducing-fresco-a-new-image-library-for-android/
I hope that helped.
Good luck.
As the commenters pointed out pending responses from Picasso might be holding you up. If that is the case, you can solve it by extending ImageView and overriding the following method. I think it is worth trying.
#Override
protected void onDetachedFromWindow() {
Picasso.with(context).cancelRequest(this);
super.onDetachedFromWindow();
}
Update:
Turns out this is not the correct way, anyone wanting to cancel requests should do so in the onViewRecycled() callback as pointed out in the comments below.
By digging deeper in Sam Judd's answer I forced recycler to recycle the views by implementing the followings in its adapter.
#Override
public boolean onFailedToRecycleView(#NonNull VH holder)
return true;
}
As you can see here:
Called by the RecyclerView if a ViewHolder created by this Adapter cannot be recycled due to its transient state. Upon receiving this callback, Adapter can clear the animation(s) that effect the View's transient state and return true so that the View can be recycled. Keep in mind that the View in question is already removed from the RecyclerView.
In some cases, it is acceptable to recycle a View although it has transient state. Most of the time, this is a case where the transient state will be cleared in onBindViewHolder(ViewHolder, int) call when View is rebound to a new position. For this reason, RecyclerView leaves the decision to the Adapter and uses the return value of this method to decide whether the View should be recycled or not.
Note that when all animations are created by RecyclerView.ItemAnimator, you should never receive this callback because RecyclerView keeps those Views as children until their animations are complete. This callback is useful when children of the item views create animations which may not be easy to implement using an RecyclerView.ItemAnimator.
You should never fix this issue by calling holder.itemView.setHasTransientState(false); unless you've previously called holder.itemView.setHasTransientState(true);. Each View.setHasTransientState(true) call must be matched by a View.setHasTransientState(false) call, otherwise, the state of the View may become inconsistent. You should always prefer to end or cancel animations that are triggering the transient state instead of handling it manually.
For anyone else looking for a quick hack,
Do this. This will delay selection until it's been inflated and selected.
I don't know how but it works.
Just return null on onFocusSearchFailed.
/**
* Created by sylversphere on 15-04-22.
*/
public class SomeGridLayoutManager extends GridLayoutManager{
private final Context context;
public SomeGridLayoutManager(Context context, int spanCount) {
super(context, spanCount);
this.context = context;
}
public SomeGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) {
super(context, spanCount, orientation, reverseLayout);
this.context = context;
}
#Override
public View onFocusSearchFailed(View focused, int focusDirection, RecyclerView.Recycler recycler, RecyclerView.State state) {
return null;
}
}