Handling Nested ViewPager swipe - android

I am in a need of nested viewPagers, I am using a custom vertical viewPager where its child is a viewPager.
My problem is when the user swipes in vertical direction (Y axis) parent viewpager should function and if he swipes in horizontal (X axis) child viewpager has to function.
I came across a lot of tutorial where I can disable either parent's swipe or child's swipe but I dont want to do that, instead according to the swipe direction either parent (vertical) should work and child (horizontal) has to work.
I have also attached parent's viewpager adapter code here
class VerticalPageAdapter extends PagerAdapter
{
Context mContext;
LayoutInflater mLayoutInflater;
public VerticalPageAdapter(Context context)
{
mContext = context;
mLayoutInflater = LayoutInflater.from(context);
}
#Override
public int getCount()
{
return 5;
}
#Override
public boolean isViewFromObject(View view, Object object)
{
return view == ((LinearLayout) object);
}
#Override
public Object instantiateItem(ViewGroup container, int position)
{
mVerticalViewPagerPosition = position;
View itemView = mLayoutInflater.inflate(R.layout.homelayout_verticalpager, container, false);
mPager = (ViewPagerTest)itemView.findViewById(R.id.pager);
mPager.setAdapter(new NewsPageAdapter(mContext));
mPager.setOnTouchListener(gestureListener);
mPager.getParent().requestDisallowInterceptTouchEvent(false);
container.addView(itemView);
return itemView;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object)
{
container.removeView((LinearLayout) object);
}
}
Please help to sort out this.

Related

How to refresh image at before position in viewPager?

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.

How to retain ViewPager state inside a RecyclerView?

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.

How to implement Fragment into ViewPager?

I try to implement Fragment into ViewPager to make my app more flexible. My app contains TextView and I have a few phrases that will appear one by one if you swap the page from left to right. For now it works in this way like I posted but I want to add a button or maybe some more function, that's why I want to make it like constructor from Fragments.. I try to change my code watching on this post but can't totally understand how to do it. I created two layouts: one for text view another one to put there fragment. Could any one show me how to do it clear?
public class SwipeAdapter extends PagerAdapter{
private int[] car = {R.string.car1, R.string.car2,
R.string.car3, R.string.car4, R.string.car5};
private Context context;
private LayoutInflater layoutInflater;
public SwipeAdapter(Context context){
this.context = context;
}
#Override
public int getCount() {
return car.length;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return (view==(RelativeLayout)object);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
layoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View itemView = layoutInflater.inflate(R.layout.carSwipe, container, false);
TextView textView = (TextView) itemView.findViewById(R.id.interTextView);
textView.setText(car[position]);
container.addView(itemView);
return itemView;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((RelativeLayout)object);
}
You don't need ViewPager with Fragments to Achieve of showing a TextView.
You can try:
In your activity layout xml that you set in content View add a ViewPager with width and height of your preference.
Then you can set the adapter that you have posted above for that ViewPager and it will work.
Alternatively if you still need to inflate Fragments then you need to extend FragmentStateAdapter of FragmentAdapter. That will give you the ability to have in the ViewPager Fragment,

How to set viewpager to change page automatically after 5 sec

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.

Android PageTransformer kills View functionality

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.

Categories

Resources