I have an image view. I want to touch the image and drag it to left or right. When the image is dragged to the left, the new image should appear from the array. When i drag it to right it should be saved in another activity. How can i possibly do this, if somebody could guide me to a tutorial or example. Thank-you
You can use ViewPager and PageAdapter.
protected class ImagePagerAdapter extends PagerAdapter {
public ImagePagerAdapter() {
}
#Override
public int getCount() {
return getImages().size();
}
#Override
public boolean isViewFromObject(View view, Object o) {
return view == o;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
LayoutInflater inflater = (LayoutInflater) container.getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.image_page_view, null);
String url = getImages().get(position);
if (url != null) {
ImageLoader.getInstance().displayImage(url, (ImageView) view.findViewById(R.id.image_page_view));
}
container.addView(view, 0);
return view;
}
}
...
imagePager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int i, float v, int i2) {
}
#Override
public void onPageSelected(int i) {
//logic to open activity or other action..;
}
#Override
public void onPageScrollStateChanged(int i) {
}
});
...
imagePager.setAdapter(new ImagePagerAdapter());
Related
Good morning,
I have a Fragment which its layout has a ViewPager, I provide a custom PageAdapter to show two child layouts. One layout is to fill with personal data and another layout is to fill with Address data by the user. On my fragment I want to retrieve both layouts data and fill a object Pessoa(Person) with an attribute Endereco (Address). So far my ViewPager is working and both layout are displayed, however when I try to get the fields on both layouts, either on onCreateView or onResume fragment's method, using :
viewpager.getChildAt(0).findViewById(R.id.txt1)
I got an NullPointerException, but if I add an OnPageChangeListener this works, I not sure if it's the best approach. Is There a best place to retrieve a reference to the viewpager child's layout?
Ps. I don't want to use two other Fragments in order to display each of the layouts.
PageAdapter
public class ViewPagerCadastroPessoaAdapter extends PagerAdapter {
private Context context;
private int[] views = {R.layout.layout_cadastro_dados_pessoais,R.layout.layout_cadastro_endereco };
public ViewPagerCadastroPessoaAdapter(Context context) {
this.context = context;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
LayoutInflater inflater = LayoutInflater.from(this.context);
View layout = inflater.inflate(views[position], container, false);
container.addView(layout, position);
return layout;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
#Override
public int getCount() {
return 2;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position){
case 0:
return "Dados Pessoais";
case 1:
return "Endereço";
}
return super.getPageTitle(position);
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}}
ViewPager's holder Fragment
public class CadastroPessoaFragment extends Fragment {
private ViewPager viewPagerCadastroPessoa;
private TabLayout tabLayoutCadastroPessoa;
public CadastroPessoaFragment() {
}
public static CadastroPessoaFragment newInstance() {
return new CadastroPessoaFragment();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_cadastro_pessoa, container, false);
tabLayoutCadastroPessoa = root.findViewById(R.id.tabLayoutCadastroPessoa);
viewPagerCadastroPessoa = root.findViewById(R.id.viewPagerCadastroPessoa);
viewPagerCadastroPessoa.setOffscreenPageLimit(2);
viewPagerCadastroPessoa.setAdapter(new ViewPagerCadastroPessoaAdapter(getContext()));
tabLayoutCadastroPessoa.setupWithViewPager(viewPagerCadastroPessoa);
int cor = ContextCompat.getColor(getContext(), android.R.color.white);
tabLayoutCadastroPessoa.setTabTextColors(cor, cor);
//get a null pointer
viewPagerCadastroPessoa.getChildAt(0).findViewById(R.id.txt1);
viewPagerCadastroPessoa.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
//works fine
viewPagerCadastroPessoa.getChildAt(0).findViewById(R.id.txt1);
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
return root;
}
#Override
public void onResume() {
super.onResume();
//get a null pointer
viewPagerCadastroPessoa.getChildAt(0).findViewById(R.id.txt1);
}
}
Thank you all in advance
UPDATE
According with
Anton Malyshev answer
The way Viewpager creates its pages is kind of "unsynchronized", so I used the following approach to solve my problem:
On my custom adapter I definied an interface with a single method onViewPagerReady(), as my Viewpager will always have only two pages, inside instantiateItem I check when position is 1 (once position starts with 0), if position == 1 I call the method onViewPagerReady that my fragment viewpager's holder implements, so inside this method I retrieve the layout of viewpager's children
public class ViewPagerCadastroPessoaAdapter extends PagerAdapter {
public interface ViewPagerObserver{
void onViewPagerReady();
}
private Context context;
private int[] views = {R.layout.layout_cadastro_dados_pessoais,R.layout.layout_cadastro_endereco };
private ViewPagerObserver observer;
public ViewPagerCadastroPessoaAdapter(Context context, ViewPagerObserver observer) {
this.context = context;
this.observer = observer;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
LayoutInflater inflater = LayoutInflater.from(this.context);
View layout = inflater.inflate(views[position], container, false);
container.addView(layout, position);
if(position == 1){
observer.onViewPagerReady();
}
return layout;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
#Override
public int getCount() {
return 2;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position){
case 0:
return "Dados Pessoais";
case 1:
return "Endereço";
}
return super.getPageTitle(position);
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
}
Fragment Viewpager's Holder
#Override
public void onViewPagerReady() {
View rootCadastroDadosPessoais = viewPagerCadastroPessoa.getChildAt(0);
View rootCadastroEnderecos =viewPagerCadastroPessoa.getChildAt(1);
}
Thank you all.
Just wait until viewPagerCadastroPessoa.getChildCount() will be greater than 0. The pages in ViewPager are not created yet in onResume (they are created asynchronously).
I have a problem with my ViewPager Image slider gallery. I am setting my page limit to 3 but then my app craches on the third image because the child has already a parent. I set the limit to this number because I want to avoid large memory leaks, event with 3 images it uses up like 150Mb of allocated memory which is incredibly huge ammount. Maybe if I resize the image before uploading I can get them to work with more pages ? Anyways, here is my code for the viewPager:
ViewPager mViewPager = (ViewPager) findViewById(R.id.imagepager);
ViewerAdapter adapter = new ViewerAdapter(this);
//adapter.notifyDataSetChanged();
mViewPager.setAdapter(adapter);
mViewPager.setOffscreenPageLimit(3);
mViewPager.setCurrentItem(number);
mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
time.setText(caluculateTimeAgo(MainActivity.time[position]));
if (MainActivity.distances[position] < 1000) {
dist.setText(String.valueOf(MainActivity.distances[position]) + "m");
} else {
long f = (long) (MainActivity.distances[position] / 1000);
dist.setText(String.valueOf(f) + "km");
}
author.setText(MainActivity.users[position]);
text.setText(MainActivity.text1[position]+MainActivity.tags[position]);
}
#Override
public void onPageSelected(int position) {
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
and here is my adapter definition:
public class ViewerAdapter extends PagerAdapter {
Context mContext;
public ViewerAdapter(Context context) {
mContext = context;
mLayoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
LayoutInflater mLayoutInflater;
#Override
public int getCount() {
return MainActivity.imgLink.length;
}
#Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == (View) arg1;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
Picasso.with(container.getContext()).cancelRequest((ImageView) object);
}
#Override
public CharSequence getPageTitle(int position) {
return (position + "/" + getCount());
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
final View itemView = mLayoutInflater.inflate(R.layout.pager_item,container,false);
final ImageView photo = (ImageView) itemView.findViewById(R.id.photoSlide);
photo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
fullscreen = ((BitmapDrawable)photo.getDrawable()).getBitmap();
Intent intent = new Intent(ShowMarkerContent.this, FullScreenImageActivity.class);
startActivity(intent);
}
});
Picasso.with(container.getContext()).load("MyWebsite" + MainActivity.imgLink[position]).into(photo);
container.addView(photo);
return photo;
}
}
Well, I managed to make a work-around for this problem. I forgot to set the cropping of the photo and therefore the photos were too large for this. And also, I set the offScreenPageLimit to 30 to avoid this error (This is that work-around because with large quantity of image it will come to out of memory error) So now, here is my adapter code:
#Override
public Object instantiateItem(ViewGroup container, int position) {
final View itemView = mLayoutInflater.inflate(R.layout.pager_item,container,false);
final ImageView photo = (ImageView) itemView.findViewById(R.id.photoSlide);
photo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
fullscreen = ((BitmapDrawable)photo.getDrawable()).getBitmap();
Intent intent = new Intent(ShowMarkerContent.this, FullScreenImageActivity.class);
startActivity(intent);
}
});
Picasso.with(container.getContext()).load("MyWebsite" + MainActivity.imgLink[position]).fit().centerCrop().into(photo);
container.addView(itemView);
return itemView;
}
I`m trying to implement ImageGallery on Android. I use AndroidTouchGallery library. In MainActyvity I have list of images and by clicking on them open AndroidTouchGallery. Everything work, but when open the image gallery starts with the first one.
There need to set the image position, in which to start. In this stage I have a problem. Maybe someone how to make it.
int pos ; //Picture Position
UrlPagerAdapter pagerAdapter = new UrlPagerAdapter(Full_Image_Activity.this, ArrayImgBig);
mViewPager = (GalleryViewPager)findViewById(R.id.viewer);
mViewPager.setOffscreenPageLimit(3);
mViewPager.setAdapter(pagerAdapter);
The code of UrlPageAdapter. I try to set the position in setPrimaryItem, but it still open the first image.
/**
Class wraps URLs to adapter, then it instantiates {#link UrlTouchImageView} objects to paging up through them.
*/
public class UrlPagerAdapter extends BasePagerAdapter {
public UrlPagerAdapter(Context context, List<String> resources)
{
super(context, resources);
}
#Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container, position, object);
((GalleryViewPager)container).mCurrentView = ((UrlTouchImageView)object).getImageView();
}
#Override
public Object instantiateItem(ViewGroup collection, int position){
final UrlTouchImageView iv = new UrlTouchImageView(mContext);
iv.setUrl(mResources.get(position));
iv.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
collection.addView(iv, 0);
return iv;
}
}
BasePagerAdapter
/**
Class wraps URLs to adapter, then it instantiates <b>UrlTouchImageView</b> objects to paging up through them.
*/
public class BasePagerAdapter extends PagerAdapter {
protected final List<String> mResources;
protected final Context mContext;
protected int mCurrentPosition = -1;
protected OnItemChangeListener mOnItemChangeListener;
public BasePagerAdapter()
{
mResources = null;
mContext = null;
}
public BasePagerAdapter(Context context, List<String> resources)
{
this.mResources = resources;
this.mContext = context;
}
#Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container, position, object);
if (mCurrentPosition == position) return;
GalleryViewPager galleryContainer = ((GalleryViewPager)container);
if (galleryContainer.mCurrentView != null) galleryContainer.mCurrentView.resetScale();
mCurrentPosition = position;
if (mOnItemChangeListener != null) mOnItemChangeListener.onItemChange(mCurrentPosition);
}
#Override
public void destroyItem(ViewGroup collection, int position, Object view){
collection.removeView((View) view);
}
#Override
public int getCount()
{
return mResources.size();
}
#Override
public boolean isViewFromObject(View view, Object object){
return view.equals(object);
}
#Override
public void finishUpdate(ViewGroup arg0){
}
#Override
public void restoreState(Parcelable arg0, ClassLoader arg1){
}
#Override
public Parcelable saveState(){
return null;
}
#Override
public void startUpdate(ViewGroup arg0) { }
public int getCurrentPosition() { return mCurrentPosition; }
public void setOnItemChangeListener(OnItemChangeListener listener) { mOnItemChangeListener = listener; }
public static interface OnItemChangeListener
{
public void onItemChange(int currentPosition);
}
}
Olso I have some other queston.
*is the "setPrimaryItem" set up the main Item(Image) witch is open first?
*is the "instantiateItem" initialise every item from the array, whitch is shows?
I made it by this:
mViewPager = (GalleryViewPager)findViewById(R.id.viewer);
mViewPager.setOffscreenPageLimit(3);
mViewPager.setAdapter(pagerAdapter);
//set position
mViewPager.setCurrentItem(pos);
For example: I have 2 pages in PageAdapter. When I go to second page, I click on button "Lock" and horizontal scrolling is off. I click "Unlock" and again can scrolling. How block scrolling ?
Code:
public class slide extends PagerAdapter
{
List<View> pages = null; // empty list views
public slide (List<View> page)
{
this.pages = page;
}
#Override
public int getCount()
{
return pages.size();
}
#Override
public boolean isViewFromObject(View view, Object obj)
{
return view.equals(obj);
}
#Override
public Object instantiateItem (View views, int position)
{
View v = pages.get(position);
((ViewPager) views).addView(v, 0);
return v;
}
#Override
public void destroyItem(View views, int position, Object view)
{
((ViewPager) views).removeView((View) view);
}
#Override
public void finishUpdate(View view)
{
}
#Override
public void restoreState(Parcelable arg0, ClassLoader arg1)
{
}
#Override
public Parcelable saveState()
{
return null;
}
#Override
public void startUpdate(View view)
{
}
In Activity:
List<View> pages = new ArrayList<View>();
View page = inflater.inflate(R.layout.page, null);
TextView textView = (TextView) page.findViewById(R.id.text_view);
textView.setText("Page 1"); // first page
pages.add(page);
page = new surfaceControl(this); // second page with some modul
pages.add(page);
slide pageAdapter = new slide(pages);
ViewPager viewPager = new ViewPager(this);
viewPager.setAdapter(pageAdapter);
viewPager.setCurrentItem(0);
This question already has answers here:
Why `PagerAdapter::notifyDataSetChanged` is not updating the View?
(43 answers)
Closed 10 years ago.
I am using ViewPager to allow user to swipe between its views. Is there a way how to force this ViewPager to reload/re-instantiate its views in case that they are no longer valid or needs to be refreshed? I tried to call notifyDataSetChanged() on its adapter but this does not invoke instantiateItem() method again.
EDIT
Here is the class that extends from ViewPager and its adapter definision. Bellow is the refresh() method that I call when I want to force to refresh items.
public class DayFlipper extends ViewPager {
public class FlipperAdapter extends PagerAdapter {
#Override
public int getCount() {
return DayFlipper.DAY_HISTORY;
}
#Override
public void startUpdate(View container) {
}
#Override
public Object instantiateItem(View container, int position) {
Log.d(TAG, "instantiateItem(): " + position);
Date d = DateHelper.getBot();
for (int i = 0; i < position; i++) {
d = DateHelper.getTomorrow(d);
}
d = DateHelper.normalize(d);
CubbiesView cv = new CubbiesView(mContext);
cv.setLifeDate(d);
((ViewPager) container).addView(cv, 0);
// add map
cv.setCubbieMap(mMap);
cv.initEntries(d);
return cv;
}
#Override
public void destroyItem(View container, int position, Object object) {
((ViewPager) container).removeView((CubbiesView) object);
}
#Override
public void finishUpdate(View container) {
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == ((CubbiesView) object);
}
#Override
public Parcelable saveState() {
return null;
}
#Override
public void restoreState(Parcelable state, ClassLoader loader) {
}
}
...
public void refresh() {
getAdapter().notifyDataSetChanged();
}
}
Had the same problem. For me it worked to call
viewPage.setAdapter( adapter );
again which caused reinstantiating the pages again.
I have found a solution. It is just a workaround to my problem but currently the only solution.
ViewPager PagerAdapter not updating the View
public int getItemPosition(Object object) {
return POSITION_NONE;
}
Does anyone know whether this is a bug or not?
public class DayFlipper extends ViewPager {
private Flipperadapter adapter;
public class FlipperAdapter extends PagerAdapter {
#Override
public int getCount() {
return DayFlipper.DAY_HISTORY;
}
#Override
public void startUpdate(View container) {
}
#Override
public Object instantiateItem(View container, int position) {
Log.d(TAG, "instantiateItem(): " + position);
Date d = DateHelper.getBot();
for (int i = 0; i < position; i++) {
d = DateHelper.getTomorrow(d);
}
d = DateHelper.normalize(d);
CubbiesView cv = new CubbiesView(mContext);
cv.setLifeDate(d);
((ViewPager) container).addView(cv, 0);
// add map
cv.setCubbieMap(mMap);
cv.initEntries(d);
adpter = FlipperAdapter.this;
return cv;
}
#Override
public void destroyItem(View container, int position, Object object) {
((ViewPager) container).removeView((CubbiesView) object);
}
#Override
public void finishUpdate(View container) {
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == ((CubbiesView) object);
}
#Override
public Parcelable saveState() {
return null;
}
#Override
public void restoreState(Parcelable state, ClassLoader loader) {
}
}
...
public void refresh() {
adapter().notifyDataSetChanged();
}
}
try this.