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;
}
}
Related
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.
This is a code I downloaded from here. It is storing the images in an array and is displayed accordingly when I run it. I want to store the images in a matrix and do that. i.e. swipe up,down,right,left for different images. I also want to skip some positions in the matrix. some sort of picture-map kind of thing. Is it possible editing this code? Or will I have to use a completely new syntax? How do I do it?
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewPager viewPager = (ViewPager) findViewById(R.id.view_pager);
ImagePagerAdapter adapter = new ImagePagerAdapter();
viewPager.setAdapter(adapter);
}
private class ImagePagerAdapter extends PagerAdapter {
private int[] mImages = new int[] {
R.drawable.chiang_mai,
R.drawable.himeji,
R.drawable.petronas_twin_tower,
R.drawable.ulm
};
#Override
public int getCount() {
return mImages.length;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == ((ImageView) object);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Context context = MainActivity.this;
ImageView imageView = new ImageView(context);
int padding = context.getResources().getDimensionPixelSize(
R.dimen.padding_medium);
imageView.setPadding(padding, padding, padding, padding);
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setImageResource(mImages[position]);
((ViewPager) container).addView(imageView, 0);
return imageView;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
((ViewPager) container).removeView((ImageView) object);
}
}
}
All depends on the number of pictures you have.
If there are not so many, you could give TableLayout a try. However, this implies starting over. You will have to implement scrolling, for instance, yourself.
If there are many pictures, you will have to work with (one or two) adapter classes. I believe there are two basic options.
You could reuse the code you have, make as many ImagePagerAdapter s as you want to have rows, put those adapters into an array which could be the data for a VerticalViewPager (https://github.com/castorflex/VerticalViewPager, for instance). This is probably the most difficult solution, but you will also learn a lot.
You could implement a GridView which is scrollable in two dimensions and needs an adapter, a BaseAdapter for example, which is different from the adapter you have in your code. However, if you can manage the skipping of positions (which you write about and which I don't really understand) in a one-dimensional array, too, this is a viable solution.
I was using Glide to load images into PhotoView to create a visualization with zoom and multiple pages, however even setting the format to DecodeFormat.PREFER_ARGB_8888 the image quality is bad when zooming.
Then I went to Picasso, however it is causing Out of Memory exception for images with 1028 x 1580 pixels. How can I display this images in a better quality, allowing zooming and switching pages (if I display them on a WebBrowser, the quality is better even when zooming)?
Here is the code of the PagerAdapter:
static class SamplePagerAdapter extends PagerAdapter {
private final List<Uri> pageList;
public SamplePagerAdapter(List<Uri> pageList) {
this.pageList = pageList;
}
#Override
public int getCount() {
return pageList.size();
}
#Override
public View instantiateItem(ViewGroup container, int position) {
PhotoView photoView = new PhotoView(container.getContext());
/*Glide.with(container.getContext())
.load(pageList.get(position))
.asBitmap()
.format(DecodeFormat.PREFER_ARGB_8888)
.into(photoView);*/
Picasso.with(container.getContext()).load(pageList.get(position)).into(photoView);
// Now just add PhotoView to ViewPager and return it
container.addView(photoView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
return photoView;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
}
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.