InfiniteViewPager freezes on setCurrentItem() method - android

I am using this code to create InfiniteViewPager:
pAdapter = new InfinitePagerAdapter(new MyPagerAdapter());
InfinitivePAdapter = (InfiniteViewPager) findViewById(R.id.pager);
InfinitivePAdapter.setAdapter(pAdapter);
There seems to be something wrong with setCurrentItem() function.
The program freezes when I try call setCurrentItem() function, but not everytime. The program freezes only when:
The setCurrentItem()'s item is lower and it is called from different method(in my case from onClickListener).
InfinitivePAdapter.setCurrentItem(7);//item is set on 7
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
InfinitivePAdapter.setCurrentItem(5);//when button is pressed it is set to 5
}
});
However program seems to be working normal when:
Item is bigger then previous one:
InfinitivePAdapter.setCurrentItem(3);//item is set on 3
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
InfinitivePAdapter.setCurrentItem(12);//when button is pressed it is set to 12
}
});
or the setCurrentItem(3) is called one after another even though the item is smaller than previous one:
InfinitivePAdapter.setCurrentItem(7);
InfinitivePAdapter.setCurrentItem(5);
More precisely program freezes in InfiniteViewPager class on this line:
#Override
public void setCurrentItem(int item) {
// offset the current item to ensure there is space to scroll
item = getOffsetAmount() + (item % getAdapter().getCount());
super.setCurrentItem(item);//<---HERE
}
I got my InfiniteViewPager from https://github.com/antonyt/InfiniteViewPager
You can download full code here:https://drive.google.com/folderview?id=0B3LJrVAKNLR1OG8yeERyQ2ZySU0&usp=sharing
Thanks!

I figured it out. In the InfinitePagerAdapter class I just changed the return value of getCount() method.
#Override
public int getCount() {
return Integer.MAX_VALUE;
}
Integer.MAX_VALUE was too big of a value so scale it down to 3000:
return 3000;//Or something similar
The problem was in the ViewPager class where on line 1029 the for loop would never finished:
for (int pos = mCurItem + 1; pos < N; pos++)
//N is the return Integer.MAX_VALUE and the mCurItem is the item set in setCurrentItem() method

Related

Item animation stopping in recyclerview when scrolled off the view android

I have a Recyclerview, im animating a view inside individual list item, but when I scroll the recyclerview the animation is stopping. Its because recyclerview removes the items form its view so when we scroll back it fetches it back! But now i want that animation to keep going as I would stop it only when i get data from server!
All I want is the animation that I start in the individual items inside the recylerview shouldn't stop even if the recyclerview is scrolled and the view is out of focus and comes back to focus! I need to stop the animation in the code when I get the server data! I have the code where to stop the animation and it works if the item is not scrolled off the view!
btn.onClick -- this button is the onClick for the recyclerview list
item 1 btn.startAnimation(anim.xml) -- starting the animation
onSuccess -- server returns success btn.clearAnimation();
but before the onSuccess if we scroll the list the animation is stopped!
Please help!
By inspiring from crymson's answer i have made little easy and useful solution using tag method of View instead setting a boolean in complicated logic of your custom adapter.
#Override
public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) {
super.onViewDetachedFromWindow(holder);
if (holder.getItemViewType() == TYPE_AD)
((ViewHolderForAd) holder).ivStory.setTag(false);
}
public class ViewHolderForAd extends RecyclerView.ViewHolder {
private ImageView ivStory;
TextView tvName;
public ViewHolderForAd(View view) {
super(view);
ivStory = (ImageView) view.findViewById(R.id.ivStoryImage);
tvName = (TextView) view.findViewById(R.id.tvAppName);
view.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
int pos = getAdapterPosition();
if (pos < 0) {
pos = (int) v.getTag();
}
customItemClickListener.onItemClicked(v, pos);
}
});
//ivStory.startAnimation(AnimationUtils.loadAnimation(context, R.anim.pulse_story));
ivStory.setTag(false); //Set default tag false to decrease risk of null
}
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int i) {
//...Your code...
if (!(boolean) holder1.ivStory.getTag()) {
holder1.ivStory.setTag(true);
holder1.ivStory.startAnimation(AnimationUtils.loadAnimation(context, R.anim.pulse_story));
}
//...Your code...//
}
You can use setTag(key, object) instead of setTag(object) if you already tagged something(like position) in your imageView.
Hope this helps someone.
Hard to give you a full solution but have you tried saving the animation state inside the ViewHolder that you are using? I'd recommend saving a boolean flag in the ViewHolder class you defined like isAnimating which is initially set to false and in your onBindViewHolder(...) method you can do something like
if (viewHolder.isAnimating) {
// start animation
} else {
// clear animation
}
viewHolder.btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
viewHolder.isAnimating = true;
// start animation
}
});

How to reset a click counter?

I have an implementation where, on every click of a button, a counter is increased and the counter is shown in a TextView. There's a reset button that is supposed to set the counter back to 0, so that the count can start again from zero when the btn_take_photo button is pressed. Here's my code:
private int counter = 0;
btn_take_photo.setOnClickListener(new FloatingActionButton.OnClickListener() {
#Override
public void onClick(View view) {
counter++;
count.setText(String.valueOf(counter));
}
});
This is the method called by the button (btn_approve) that is supposed to reset the counter:
public void btn_aprove (View view)
{ count.setText("0");
}
When I click btn_approve, the TextView shows 0. But, when I press btn_take_photo again, the counter starts from the last set value instead of 1. For instance, if I reset the counter when count is 6, the TextView reads 0. Then if I press btn_take_photo, the counter shows 6 again.
You also have to set the variable counter back to 0.
So your "Reset"-function should look like this:
public void btn_aprove (View view)
{
count.setText("0");
counter = 0;
}
You must also reset counter = 0;

How to open a new activity which has list of item at specific position in android [duplicate]

How can I programmatically scroll to a specific position in a ListView?
For example, I have a String[] {A,B,C,D....}, and I need to set the top visible item of the ListView to the index 21 of my String[].
For a direct scroll:
getListView().setSelection(21);
For a smooth scroll:
getListView().smoothScrollToPosition(21);
For a SmoothScroll with Scroll duration:
getListView().smoothScrollToPositionFromTop(position,offset,duration);
Parameters
position -> Position to scroll to
offset ---->Desired distance in pixels of position from the top of the view when scrolling is finished
duration-> Number of milliseconds to use for the scroll
Note: From API 11.
HandlerExploit's answer was what I was looking for, but My listview is quite lengthy and also with alphabet scroller. Then I found that the same function can take other parameters as well :)
Edit:(From AFDs suggestion)
To position the current selection:
int h1 = mListView.getHeight();
int h2 = listViewRow.getHeight();
mListView.smoothScrollToPositionFromTop(position, h1/2 - h2/2, duration);
Put your code in handler as follows,
public void timerDelayRunForScroll(long time) {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
try {
lstView.smoothScrollToPosition(YOUR_POSITION);
} catch (Exception e) {}
}
}, time);
}
and then call this method like,
timerDelayRunForScroll(100);
CHEERS!!!
The Listview scroll will be positioned to top by default, but want to scroll if not visible then use this:
if (listView1.getFirstVisiblePosition() > position || listView1.getLastVisiblePosition() < position)
listView1.setSelection(position);
I have set OnGroupExpandListener and override onGroupExpand() as:
and use setSelectionFromTop() method which
Sets the selected item and positions the selection y pixels from the top edge of the ListView. (If in touch mode, the item will not be selected but it will still be positioned appropriately.) (android docs)
yourlist.setOnGroupExpandListener (new ExpandableListView.OnGroupExpandListener()
{
#Override
public void onGroupExpand(int groupPosition) {
expList.setSelectionFromTop(groupPosition, 0);
//your other code
}
});
If someone looking for a similar functionality like Gmail app,
The Listview scroll will be positioned to top by default. Thanks for the hint.
amalBit.
Just subtract it. That's it.
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
int h1 = mDrawerList.getHeight();
int h2 = header.getHeight();
mDrawerList.smoothScrollToPosition(h2-h1);
}
}, 1000);
If you want to jump directly to the desired position in a listView just use
listView.setSelection(int position);
and if you want to jump smoothly to the desired position in listView just use
listView.smoothScrollToPosition(int position);
Handling listView scrolling using UP/ Down using.button
If someone is interested in handling listView one row up/down using button. then.
public View.OnClickListener onChk = new View.OnClickListener() {
public void onClick(View v) {
int index = list.getFirstVisiblePosition();
getListView().smoothScrollToPosition(index+1); // For increment.
}
});
This is what worked for me. Combination of answers by amalBit & Melbourne Lopes
public void timerDelayRunForScroll(long time) {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
try {
int h1 = mListView.getHeight();
int h2 = v.getHeight();
mListView.smoothScrollToPositionFromTop(YOUR_POSITION, h1/2 - h2/2, 500);
} catch (Exception e) {}
}
}, time);
}
and then call this method like:
timerDelayRunForScroll(400);
-If you just want the list to scroll up\dawn to a specific position:
myListView.smoothScrollToPosition(i);
-if you want to get the position of a specific item in myListView:
myListView.getItemAtPosition(i);
-also this myListView.getVerticalScrollbarPosition(i);can helps you.
Good Luck :)
You need two things to precisely define the scroll position of a listView:
To get the current listView Scroll position:
int firstVisiblePosition = listView.getFirstVisiblePosition();
int topEdge=listView.getChildAt(0).getTop(); //This gives how much the top view has been scrolled.
To set the listView Scroll position:
listView.setSelectionFromTop(firstVisiblePosition,0);
// Note the '-' sign for scrollTo..
listView.scrollTo(0,-topEdge);
it is easy
list-view.set selection(you pos);
or you can save your position with SharedPreference and when you start activity
it get preferences and setSeletion to that int
I found this solution to allow the scroll up and down using two different buttons.
As suggested by #Nepster I implement the scroll programmatically using the getFirstVisiblePosition() and getLastVisiblePosition() to get the current position.
final ListView lwresult = (ListView) findViewById(R.id.rds_rdi_mat_list);
.....
if (list.size() > 0) {
ImageButton bnt = (ImageButton) findViewById(R.id.down_action);
bnt.setVisibility(View.VISIBLE);
bnt.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(lwresult.getLastVisiblePosition()<lwresult.getAdapter().getCount()){
lwresult.smoothScrollToPosition(lwresult.getLastVisiblePosition()+5);
}else{
lwresult.smoothScrollToPosition(lwresult.getAdapter().getCount());
}
}
});
bnt = (ImageButton) findViewById(R.id.up_action);
bnt.setVisibility(View.VISIBLE);
bnt.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(lwresult.getFirstVisiblePosition()>0){
lwresult.smoothScrollToPosition(lwresult.getFirstVisiblePosition()-5);
}else{
lwresult.smoothScrollToPosition(0);
}
}
});
}

Does android PageAdapter and ViewPager check for indexoutofbounds exception when using setCurrentItem(int index)?

So my activity uses the PageAdapter and ViewPager correctly, where 3 images can be scrolled from left to right. So then I have left and right arrows on the activity and I set an onClickListener for both images to scroll left and right with ViewPager pager. The method is like
private void setOnClickArrows(final ViewPager pager){
ImageView rightArrow = (ImageView) view.findViewById(R.id.right);
ImageView leftArrow = (ImageView) view.findViewById(R.id.left);
rightArrow.setOnClickListener(new OnClickListener ()
#Override
public void onClick(View v) {
pager.setCurrentItem(pager.getCurrentItem() + 1);
}
});
leftArrow.setOnClickListener(new OnClickListener ()
#Override
public void onClick(View v) {
pager.setCurrentItem(pager.getCurrentItem() - 1);
}
});
}
This works perfectly. However, I was wondering how the ViewPager checks if the index is out of bounds and if I should do it?
Yes, it actually does. Refer to the source and have a look at the setCurrentItemInternal method (called by setCurrentItem()).
There are a few checks in place to avoid a crash, and among one of them is this, which avoids OOBExceptions:
if (item < 0) {
item = 0;
} else if (item >= mAdapter.getCount()) {
item = mAdapter.getCount() - 1;
}
Should you check yourself? Up to you. I wouldn't because those checks are trivial, so I wouldn't expect the checks to disappear.

Remove Item + Scroll to Next in Android ViewPager

I have an Activity containing a ViewPager that displays N fragments. Each fragment is showing the properties of an object from an ArrayList in my ViewPager's custom adapter (extends FragmentStatePagerAdapter).
The fragment has (among other things) a button that should remove the currently displayed fragment and scroll to the next one with setCurrentItem(position, true) so that if the user scrolls back, the previous item is gone. I do so by using something like this (simplified):
deleteButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
MyActivity parentActivity = (MyActivity)getActivity();
// First, scroll to next item (smoothly)
parentActivity.pager.setCurrentItem(parentActivity.pager.getCurrentItem()+1, true);
// Database stuff...
doSomeDBOperations();
// Method in Activity that removes the current object (I believe this method is working fine and yes, it calls notifyDataSetChanged())
parent.removeObject(currentObject);
}
});
This has the desired behavior as the object represented by the fragment whose delete button was pressed gets removed and the viewpager goes to the next page.
My problem is that the ViewPager doesn't scroll smoothly but rather "jumps instantly" to the next fragment. If I comment the removeObject() call, the smooth scroll works (but the item isn't removed). I believe it's has something to do with the removeObject() being called before the setCurrentItem() has finished the smooth scrolling animation?
Any ideas on how to fix this and achieve item removal + smooth scroll? If my assumption is correct, how can I make sure I get the smooth scroll to finish before removing the object?
EDIT 1:
My assumption seems correct. If I put the parent.removeObject(currentObject) inside
// ...inside the previously shown public void onClick(View v)...
confirm.postDelayed(new Runnable() {
#Override
public void run() {
// Method in Activity that removes the current object (I believe this method is working fine and yes, it calls notifyDataSetChanged())
parent.removeObject(currentObject);
}
}, 1000);
so that the removeObject() call waits for a second, it works as expected: scroll to the next item, remove the previous. But this is a very ugly workaround so I'd still like a better approach.
EDIT 2:
I figured out a possible solution (see below).
I ended up overriding the
public void onPageScrollStateChanged(int state)
method:
Whenever the user presses the delete button in the fragment, the listener sets a bool in the current item (flagging it for deletion) and scrolls to the next one.
When the onPageScrollStateChanged detects that the scroll state changed to ViewPager.SCROLL_STATE_IDLE (which happens when the smooth scroll ends) it checks if the previous item was marked for deletion and, if so, removes it from the ArrayList and calls notifyDataSetChanged().
By doing so, I've managed to get the ViewPager to smoothly scroll to the next position and delete the previous item when the "delete" button is pressed.
EDIT: Code snippet.
#Override
public void onPageScrollStateChanged(int state)
{
switch(state)
{
case ViewPager.SCROLL_STATE_DRAGGING:
break;
case ViewPager.SCROLL_STATE_IDLE:
int previousPosition = currentPosition - 1;
if(previousPosition < 0){
previousPosition = 0;
}
MyItem previousItem = itemList.get(previousPosition);
if(previousItem.isDeleted())
{
deleteItem(previousItem);
// deleteItem() Does some DB operations, then calls itemList.remove(position) and notifyDataSetChanged()
}
break;
case ViewPager.SCROLL_STATE_SETTLING:
break;
}
}
Have you tried ViewPager.OnPageChangeListener?
I would call removeObject(n) method in OnPageChangeListener.onPageSelected(n+1) method.
I did something different that works smoothly. The idea is to to remove the current item with animation (setting its alpha to 0), then translating horizontally the left or right item (with animation) to the now invisible item position.
After the animation is complete, I do the actual data removal and notfyDataSetChanged() call.
This remove() method I put inside a subclass of ViewPager
public void remove(int position, OnViewRemovedListener onViewRemovedListener) {
final int childCount = getChildCount();
if (childCount > 0) {
View toRemove = getChildAt(position);
int to = toRemove.getLeft();
final PagerAdapter adapter = getAdapter();
toRemove.animate()
.alpha(0)
.setDuration(getResources().getInteger(android.R.integer.config_shortAnimTime))
.setListener(new SimpleAnimatorListener() {
#Override
public void onAnimationEnd(Animator animation) {
if (childCount == 1) {
if (onViewRemovedListener != null) onViewRemovedListener.onRemoved(position, -1);
if (adapter!= null) adapter.notifyDataSetChanged();
}
}
})
.start();
if (childCount > 1) {
int newPosition = position + 1 <= childCount - 1 ? position + 1 : position - 1;
View replacement = getChildAt(newPosition);
int from = replacement.getLeft();
replacement.animate()
.setInterpolator(new DecelerateInterpolator())
.setDuration(getResources().getInteger(android.R.integer.config_mediumAnimTime))
.translationX(to - from)
.setListener(new SimpleAnimatorListener() {
#Override
public void onAnimationEnd(Animator animation) {
if (onViewRemovedListener != null) onViewRemovedListener.onRemoved(position, newPosition);
if (adapter!= null) adapter.notifyDataSetChanged();
}
})
.start();
}
}
}
public interface OnViewRemovedListener {
void onRemoved(int position, int newPosition);
}

Categories

Resources