24

So far I've been hacking together examples to get a feel for the APIs the Android SDK as a whole. However, I've hit an impasse.

I'm trying to Inflate a LinearLayout with 2 TextViews from an XML file. These will be then Views that are paged. I simply can't get this to work and realize that I totally don't understand what's going on with the code.

Looking at the source I can see that the method ViewPager.addNewItem calls the InstantiateItem from the supplied adapter. And addNewItem is called in populate(). populate() is called in a number of other places.

Anyway, in the example, I've experienced that when the method is overridden for PagerAdapter one must include a call to addView() on the ViewPager collection that is passed from the ViewPager as an argument.

If I wish to add multiple views I thought this would be a case of calling addView() more than once but as instantiateItem() returns an Object to ViewPager (in the example I had it returns the view that it added) I don't know what to return. I've tried returning the inflated view and a number of other things.

Please, can someone explain what is happening here?

Much appreciated.

@Override
public Object instantiateItem(View collection, int position) {

    layout = inflater.inflate(R.layout.animallayout, null);
    TextView tv = (TextView) layout.findViewById(R.id.textView1);
    tv.setText("1________________>" + position);

    TextView tv2 = (TextView) layout.findViewById(R.id.textView2);
    tv.setText("2________________>" + position);

    ((ViewPager) collection).addView(layout);
    return layout;
}
Daksh Gargas
  • 3,498
  • 2
  • 23
  • 37
mAndroid
  • 5,087
  • 6
  • 25
  • 33

2 Answers2

59

I've recently implemented this and this is my instantiateItem method (made it a bit minimal for readability.

@Override
public Object instantiateItem(View collection, int position) {
    Evaluation evaluation = evaluations.get(position);

    View layout = inflater.inflate(R.layout.layout_evaluation, null);

    TextView evaluationSummary = (TextView) layout.findViewById(R.id.evaluation_summary);
    evaluationSummary.setText(evaluation.getEvaluationSummary());

    ((ViewPager) collection).addView(layout);

    return layout;
}

@Override
public void destroyItem(View collection, int position, Object view) {
     ((ViewPager) collection).removeView((View) view);
}

@Override
public boolean isViewFromObject(View view, Object object) {
    return view == object;
}

So for the page that is displayed, I get the data from my evaluations list using the position as the index. Then inflate the Layout which has the views I will add my data too. Then I get the TextView to set the evaluation summary text on. Then the whole Layout is added to the ViewPager. And finally the Layout is also returned.

If you still can't get it post your code.

C0deAttack
  • 24,419
  • 18
  • 73
  • 81
  • Thanks C0de attack. I can see that you are inflating a layout. Does this have more than one view in it? I can only see that you are setting up one text view to page - I have got this to work. It's when I want to scroll 2 textviews that I start having problems. I'm also a bit confused as to how a layout inflates only to a view when it contains many views? – mAndroid Sep 02 '11 at 01:04
  • in fact could you post the XML layout for me to have a look at if that's not too much trouble. Much appreciated. – mAndroid Sep 02 '11 at 01:17
  • Looking at the isViewFromObject in PagerAdapter: if I want to use multiple views per page do I need to override this method further to do a more complete check to see if the views are part of the object returned? – mAndroid Sep 02 '11 at 01:55
  • I've added the other two methods that need to be implemented. My layout does actually have several views, I just showed one for simplicity. – C0deAttack Sep 02 '11 at 02:16
  • Thanks, I'd actually just worked that out. I've got a new problem that only one of the text views displays what I set it to in the instantiateItem method. I've added my code into the initial question. If both textViews are left in the code it displays 2__________>0 Textview2 if the second textview set text is commented out then it displays the first (1_________________>0) – mAndroid Sep 02 '11 at 02:29
  • sorry stupid mistake, I'm set tv twice. duh Thanks for your help here you don't know how much I appreciate it. – mAndroid Sep 02 '11 at 02:35
  • One more thing, it seems to be a bit inefficient to inflate the view each time the screen is swiped - do you think there is a better way to do this? I've tried moving the statement but then an error is raised to say that the textViews already have a parent. – mAndroid Sep 02 '11 at 02:45
  • 6
    Just a fix for the new version... use instantiateItem with ViewGroup instead of View... it has been depreciated in the last version. – Pozzo Apps Feb 13 '13 at 11:12
  • @ cOdeAttack can you please also show your Evaluation class. – Saad Bilal Jun 24 '14 at 11:05
  • Hmm, thanks, thats works just fine. But the onClick event act weirdly. If all pages have same Button then button event works in last page only. Any idea why? – hemantsb Jan 28 '15 at 08:48
  • The casts to `ViewPager` are redundant. – naXa stands with Ukraine Aug 07 '16 at 20:46
17

I have the same misunderstanding how this adapter works and I have made some investigation.
The key particularity is that your views are stored in two places:
1 in ViewPager you add them by calling ((ViewPager) container).addView(view); (here you need to store only three views, what you see and left and right neighborhoods)
2 in private final ArrayList<ItemInfo> mItems = new ArrayList<ItemInfo>(); this is member of ViewPager there are stored views with information about they possition (they are added here by calling adapter method mAdapter.instantiateItem(this, position);)

static class ItemInfo {
    Object object;
    int position;
    boolean scrolling;
    float widthFactor;
    float offset;
}

When you slides ViewPager gets view position from mItems array or instantiates it and compare this view with children of ViewPager with adapters method public boolean isViewFromObject(View view, Object object). View which is equals to object is displayed to user on ViewPager. If there is no view then the blank screen is displayed.
Here is ViewPager method where view is compared to object:

ItemInfo infoForChild(View child) {
    for (int i=0; i<mItems.size(); i++) {
        ItemInfo ii = mItems.get(i);
        if (mAdapter.isViewFromObject(child, ii.object)) {
            return ii;
        }
    }
    return null;
}

If views position from mItems is not in range {currentposition -1,currentposition +1} then it will be destroyed:

mItems.remove(itemIndex);
mAdapter.destroyItem(this, pos, ii.object);

the view of ViewPagers memory 1

It is one trap with destroyItem when you slides forward firs is called destroyItem and then new item is added, but when you slides backward first is added new item and then old is destroyed. If you try to use only three cached views you can get IllegalStateException: The specified child already has a parent. while sliding backwards.

ViewPager memory

Roman Nazarevych
  • 7,513
  • 4
  • 62
  • 67