I use a viewPager has images extend of PinchImageView which provide that zooming image.
When I have scrolled in position to other position in viewPager, zoomed image kept old state.
PinchImageView library link: https://github.com/boycy815/PinchImageView
How to refresh image at before position in viewPager? I've thinked that use destroyItem but didn't find how to do it.
private class MyViewPagerAdapter extends PagerAdapter {
PinchImageView photoView;
#NonNull
#Override
public Object instantiateItem(#NonNull ViewGroup container, int position) {
LayoutInflater inflater = LayoutInflater.from(getApplicationContext());
View view = inflater.inflate(R.layout.show_images, container, false);
photoView = ViewUtil.findById(view, R.id.photoView);
photoView.setViewPager(viewPager);
Image image = allImages.get(position);
if (image != null) {
String path = image.getPath();
if (hasPathControl(path)) {
setImage();
loadImage(path, photoView);
}
container.addView(view);
return view;
}
#Override
public int getCount() {
return allImages.size();
}
#Override
public boolean isViewFromObject(#NonNull View view, #NonNull Object obj) {
return view == (obj);
}
#Override
public void destroyItem(#NonNull ViewGroup container, int position, #NonNull Object object) {
Mylog.i(TAG, " destroyItem position " + position);
container.removeView((View) object);
}
private void loadImage(String path, ImageView imageView) {
glideRequests.load(path)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.dontTransform()
.override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
.transition(withCrossFade())
.into(imageView);
}
}
Moving to the other position:
Must be:
Existing:
One way of achieving this is to update/refresh the view in the ViewPager when it is the current position.
From the java doc of the source of PagerAdapter
PagerAdapter supports data set changes. Data set changes must occur on the main thread and must end with a call to {#link #notifyDataSetChanged()} similar to AdapterView adapters derived from {#link android.widget.BaseAdapter}. A data set change may involve pages being added, removed, or changing position. The ViewPager will keep the current page active provided the adapter implements the method {#link #getItemPosition(Object)}.
Add a OnPageChangeListener to your ViewPager. And on onPageSelected call the notifyDataSetChanged on your PagerAdapter.
This should call the getItemPosition of the PagerAdapter. Then add this to your PagerAdapter:
public int getItemPosition(Object object) {
return POSITION_NONE;
}
You should get the updated view at that position.
Related
I am working on an android application and using viewpager in a view. I am using PagerAdapter to show the views of tabs in viewpager.
I have to add/remove some Tabs dynamically. When I am adding any tab along with it's view then instantiateItem function is being called and tab is getting added successfully. But When I remove any tab from viewpager then destroyItem function should be called but it is not getting called and the view of Tab is not getting removed.
This the code which I am using to add/remove tabs.
public List<View> viewsList = new ArrayList();
public HashMap<Integer, View> GridViewList = new HashMap<>();
MyAdapter myAdapter = new MyAdapter();
viewPager.setAdapter(myAdapter);
viewPager.setOffscreenPageLimit(myAdapter.getCount() + 1);
private class MyAdapter extends PagerAdapter {
public MyAdapter() {
super();
}
#Override
public int getCount() {
return viewsList.size();
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
View v = viewsList.get(position).rootView;
container.addView(v, 0);
return v;
}
#Override
public void destroyItem(ViewGroup container, int position, Object view) {
container.removeView((View)view);
}
#Override
public boolean isViewFromObject(View view, Object key) {
return key == view;
}
}
I am adding using the below method When I add any Tab along with it's view
View view = new View(); // I am making Custom View here
viewsList.add(view);
GridViewList.put(Id, view);
myAdapter.notifyDataSetChanged();
And When I remove any view, I use below method :
viewsList.remove(GridViewList.get(Id));
GridViewList.remove(Id);
myAdapter.notifyDataSetChanged();
But the destroyItem function is not being called when I remove any Tab and it's view from adapter in android. Please help me if someone have any idea about this.
Thanks a lot in advanced.
Late to the party, but: you need to implement getItemPosition in order for destroyItem to be called. In this case, something like this should work:
#Override public int getItemPosition(Object itemIdentifier) {
int index = viewsList.indexOf(itemIdentifiers);
return index == -1 ? POSITION_NONE : index;
}
My RecyclerView contains many ViewPagers. The number of pages inside each ViewPager is constant (2). I use PagerAdapter.
When I scroll my RecyclerView, the ViewPagers lose their state and reset to the 1st page. I want to know how to retain the last selected page for each ViewPager.
For example:
1) I scroll to page 2 in my 1st ViewPager
2) I scroll the RecyclerView to the bottom and my 1st ViewPager goes out of screen.
3) I scroll to the top of the ViewPager and so my 1st ViewPager loads again.
4) My 1st ViewPager is set to 1st page instead of page 2 which I lastly scrolled to.
There are 'n' number of ViewPagers inside the RecyclerView and I want to retain all their states regardless of reloading due to RecyclerView.
How to solve this logic?
Well, I wrote little bit brute-force solution for this.
My PagerAdapter:
public class ViewPagerAdapter extends PagerAdapter {
#Override
public int getCount() {
return 2;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
FrameLayout layout = new FrameLayout(container.getContext());
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
layout.setLayoutParams(layoutParams);
layout.setBackgroundColor(position % 2 == 0 ? Color.RED : Color.BLUE);
container.addView(layout);
return layout;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
}
(so we the visually "state" differs in it's color - it's red in first position and blue in the second position)
The RecyclerViewAdapter looks like:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public HashMap<Integer, Integer> viewPageStates = new HashMap<>();
public RecyclerViewAdapter() {}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
return new ViewHolder(new ViewWithViewPager(viewGroup.getContext()));
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
((ViewWithViewPager) holder.itemView).refreshState(position, viewPageStates.containsKey(position)? viewPageStates.get(position) : 0);
}
#Override
public int getItemCount() {
return 42;
}
#Override
public void onViewRecycled(RecyclerView.ViewHolder holder) {
ViewWithViewPager recycledViewPager = ((ViewWithViewPager)holder.itemView);
viewPageStates.put(recycledViewPager.viewPosition, recycledViewPager.viewPager.getCurrentItem());
super.onViewRecycled(holder);
}
public class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View itemView) {
super(itemView);
}
}
}
I.e. every time we bind RecyclerView's ViewHolder, we pass the current state of the viewpager(from viewPageStates) and its order in RecyclerView's dataset.
Once it's recycled - we read its current page state and saving it into HashMap viewPageStates.
The last piece - the ViewWithViewPager
public class ViewWithViewPager extends FrameLayout {
ViewPager viewPager;
int viewPosition = 0;
public ViewWithViewPager(Context context) {
super(context);
LayoutInflater.from(context).inflate(R.layout.item_layout, this);
viewPager = (ViewPager) findViewById(R.id.viewPager);
viewPager.setAdapter(new ViewPagerAdapter());
}
public void refreshState(int position, int selectedPage) {
viewPosition = position;
viewPager.setCurrentItem(selectedPage);
}
}
I.e. in refreshState we set ViewPager to the proper page
Solution by OP.
Override onViewRecycled(ViewHolder viewHolder){} inside your
RecyclerView.Adapter
Use a HashMap to store the position of the ViewPager in the
RecyclerView and the corresponding current selected page of the
ViewPager.
Inside the onViewRecycled() method input the values to the above
created HashMap.
In the onBindViewHolder() method load the saved state/page of the
ViewPager from the HashMap using the position and set the saved
state/page to the ViewPager using the setCurrentItem() method.
Thanks to Konstantin and atabouraya.
i Want to make a slideshow with viewpager where pages are changed automatically every 5 sec. Ive done the viewpager , but got blocked till here , any advise??
Adapter.class (its inner class in my fragment)
class CustomPagerAdapter extends PagerAdapter {
Context mContext;
LayoutInflater mLayoutInflater;
public CustomPagerAdapter(Context context) {
mContext = context;
mLayoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return mResources.length;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == ((LinearLayout) object);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
View itemView = mLayoutInflater.inflate(R.layout.slide_show_item, container, false);
ImageView imageView = (ImageView) itemView.findViewById(R.id.imageView);
imageView.setImageResource(mResources[position]);
container.addView(itemView);
return itemView;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((LinearLayout) object);
}
}
}
Here is the function i call in my fragment
public void setSlideShow(){
mCustomPagerAdapter = new CustomPagerAdapter(getActivity());
mViewPager = (ViewPager)rootView.findViewById(R.id.slide_show);
mViewPager.setAdapter(mCustomPagerAdapter);
}
Well, android does not provide any function to automatically flip views inside ViewPager but it provides you with something called TimerTask class which you can use to achieve your goal.
You can look at this link to do it this way.
There is one more easy way to achieve this but for that you will have to drop the idea of using ViewPager. Instead you can use ViewFlipper.
ViewFlipper has its own methods to flip automatically. You just need to add these two lines to make your views automatically flippable:
mViewFlipper.setAutoStart(true);
mViewFlipper.setFlipInterval(2000); // flip every 2 seconds (2000ms)
You can get ViewFlipper example here.
I am using PagerSlidingTabStrip to have a ViewPager with tabs in an Android layout.
My ViewPager custom adapter is the following:
private static class SlidingPagerAdapter extends PagerAdapter implements IconTabProvider {
private final List<Tab> mItems;
private final LayoutInflater mInflator;
public SlidingPagerAdapter(Context context, List<Tab> tabs) {
mItems = tabs;
mInflator = LayoutInflater.from(context);
}
#Override
public int getCount() {
return mItems.size();
}
#Override
public boolean isViewFromObject(View v, Object obj) {
return v == (View) obj;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Tab data = mItems.get(position);
View child = mInflator.inflate(data.mLayoutResource, container, false);
container.addView((View) child, 0);
return child;
}
#Override
public int getPageIconResId(int position) {
return mItems.get(position).mIconResource;
}
}
The problem arises when I set a PageTransformer to the ViewPager. As a test I used ZoomOutPageTransformer provided in the Android docs.
When the child view from the ViewPager is first loaded, all works fine. I can click items and the views are updated. But after the first time I scroll through the ViewPager, the child views just stop rendering properly. If I click on an item, I can feel haptic feedback and click sounds but the view remains in its previous state.
I have tried invalidating the View every time there is a change in the ViewPager, but this hasn't helped.
There are similar problems when using a ListView inside a ViewPager, so I tried setting the views that are out of view as GONE, but this hasn't worked either.
I had a similar problem and I was able to fix it by following the answer on this SO question: apply PageTransformer to PagerView as soon as possible Except I used .0001f in fakeDragBy()
Hacky, but it worked.
I have ViewPager and FragmentPagerAdapter and I want to show a big amount of images with good quality. I have custom FragmentPagerAdapter and I put into it array with paths to images and then i am creating fragment for every image. The problem is in that when I have a lot of images scrolling between ViewPager items becomes too slow. What are the ways to make fast scrolling?
Resize images in a separate thread?
Use FragmentStatePagerAdapter?
Something else?
You can use PagerAdapter override destroyItem it works well for huge images:
private class ImagePagerAdapter extends PagerAdapter{
#Override
public int getCount() {
return mPhotos.size();
}
#Override
public boolean isViewFromObject(View view, Object obj) {
return obj.equals(view);
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
((ViewPager)container).removeView((View)object);
}
#Override
public Object instantiateItem(ViewGroup view, int position) {
View imageLayout = getLayoutInflater().inflate(R.layout.item_pager_image, view, false);
ImageView imageView = (ImageView) imageLayout.findViewById(R.id.image);
// set up imageView
view.addView(imageLayout, 0);
return imageLayout;
}
}