best way to use viewpager - android

I have a working viewpager example using code I got from a tutorial. The tutorial was written by Lauren Darcey and Shane Conder who are apparently experts (I am new to Android). The code is pasted below. What this code is doing is inflating (ahead) and destroying (behind) as the user swipes horizontally. There are only 5 pages. It seems that it would be much smarter to inflate them all and then let the user do all the swiping with no inflation/destruction going on. Just like it were one big wide page (such as the Panarama and Pivot controls in Windows Phone 7).
Also, this code blows if one of the pages has a google map on it. It blows on the second inflation (don't know why yet) and this wouldn't happen if they were just all inflated once.
Is there a reason why it has to be done this way? Are there any examples available on doing the way I suggest?
Thanks,
Gary Blakely
private class MyPagerAdapter extends PagerAdapter {
public int getCount() {
return 5;
}
public Object instantiateItem(View collection, int position) {
LayoutInflater inflater = (LayoutInflater) collection.getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
int resId = 0;
switch (position) {
case 0:
resId = R.layout.farleft;
break;
case 1:
resId = R.layout.left;
break;
case 2:
resId = R.layout.middle;
break;
case 3:
resId = R.layout.right;
break;
case 4:
resId = R.layout.farright;
break;
}
View view = inflater.inflate(resId, null);
((ViewPager) collection).addView(view, 0);
return view;
}
#Override
public void destroyItem(View arg0, int arg1, Object arg2) {
((ViewPager) arg0).removeView((View) arg2);
}

You can use ViewPager.setOffscreenPageLimit(int) to load all off-screen tabs. Just set it to 4 (that's 5 total, minus 1 visible) by doing ((ViewPager) collection).setOffscreenPageLimit(4); or ((ViewPager) collection).setOffscreenPageLimit(getCount() - 1);.
Keep in mind the memory implications of this; having everything loaded will run down the device's RAM if you're not careful.

Related

How to add section separators / dividers to a ListView?

I'm currently making a menu for my app, using a DrawerLayout and an ArrayAdapter subclass to achieve something looking like Facebook's drawer menu.
I currently have no problems creating the list, but now that it looks good, i'd like to add separators between different kind of options (i.e. user-related and application-related options) and a search bar on top of the menu.
The code of my current ArrayAdaptor subclass is as following :
public class DrawerMenuAdapter extends ArrayAdapter<String>{
private Context context;
private String[] values;
private int resId;
public DrawerMenuAdapter(Context context, int textViewResourceId, String[] values) {
super(context, textViewResourceId, values);
this.context = context;
this.values = values;
this.resId = textViewResourceId;
}
#Override
public View getView(int position, View convertView, ViewGroup parent){
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(this.resId, parent, false);
TextView elementText = (TextView)rowView.findViewById(R.id.element_text);
ImageView elementImage = (ImageView)rowView.findViewById(R.id.element_icon);
String textValue = values[position];
elementText.setText(textValue);
//This switch adds the icons to the related elements
switch (position){
case 0:
elementImage.setImageResource(R.drawable.search);
break;
case 1:
elementImage.setImageResource(R.drawable.facebook_friends);
break;
case 2:
elementImage.setImageResource(R.drawable.flirts_history);
break;
case 3:
elementImage.setImageResource(R.drawable.premium);
break;
case 4:
elementImage.setImageResource(R.drawable.settings);
break;
case 5:
elementImage.setImageResource(R.drawable.share_app);
break;
case 6:
elementImage.setImageResource(R.drawable.cgu);
break;
}
return rowView;
}
}
I assume that I have to override the function that populates the ListView by calling the getView function, but I can't find which function it is.
If you want simple sections in your ListView, take a look at this tutorial:
http://cyrilmottier.com/2011/07/05/listview-tips-tricks-2-section-your-listview/
or this tutorial:
http://bartinger.at/listview-with-sectionsseparators/
The second one is not as detailed, but probably easier to understand / kept simpler.
The basic idea is that you make your ListAdapter have different kinds of views. For example two different Views where one kind is the actual list item displaying the information, and the other kind of View being the Section divider.
From the tutorial:
ListViews and more specifically Adapters can handle several types of Views. If you take a look at the Adapter interface you will notice it contains two specific methods:
getViewTypeCount() which returns the number of types of Views your
AdapterView manages. Most of the time this method returns 1 because
all items of the ListView are similar. In this case, by returning 2,
the ListView will handle two types of Views: the regular item Views
and the separator Views
getItemViewType(int) must return an integer between 0 (inclusive) and
getViewTypeCount() (exclusive). The given number expresses the type
of the View at the given position. For instance, we can ensure the
returned values are 0 for the regular item Views and 1 for the
separators
I'm adding an answer here since i've figured another way to to this. It looks a bit like the links #Phil posted.
First i set a string array of the menu i want to display. I've written this array in an XML resource file for personal convenience.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array
name="drawer_menu_options">
<item>Username</item>
<item>-sep-Flirter</item>
<item>Recherche</item>
<item>Amis Facebook</item>
<item>Flirts</item>
<item>Compte premium</item>
<item>-sep-Menu</item>
<item>Réglages</item>
<item>Inviter des amis</item>
<item>CGU</item>
</string-array>
</resources>
Notice that I have two elements using the prefix -sep-. These will be our separators.
Then comes the DrawerMenuAdapter i've shown earlier, which is still an ArrayAdapter, on which I've added some functionalities :
public class DrawerMenuAdapter extends ArrayAdapter<String>{
private Context context;
private String[] values;
private int resId;
private int separatorId = 0;
private int userbarId = 0;
public DrawerMenuAdapter(Context context, int textViewResourceId, String[] values) {
super(context, textViewResourceId, values);
this.context = context;
this.values = values;
this.resId = textViewResourceId;
}
public void setSeparator(int resId){
separatorId = resId;
}
public void setUserbarId(int resId){
userbarId = resId;
}
#Override
public View getView(int position, View convertView, ViewGroup parent){
View rowView;
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if(userbarId != 0 && values[position].equals("Username")){
rowView = inflater.inflate(this.userbarId, parent, false);
}else if(separatorId != 0 && values[position].startsWith("-sep-")){
rowView = inflater.inflate(this.separatorId, parent, false);
}else{
rowView = inflater.inflate(this.resId, parent, false);
}
TextView elementText = (TextView)rowView.findViewById(R.id.element_text);
String textValue = values[position];
/* If the current line is a separator, just display a separator. Otherwise, set the
matching picture
*/
if(textValue.startsWith("-sep-")){
elementText.setText(textValue.substring("-sep-".length()));
}else{
if(textValue.equals("Username")){
elementText.setText(context.getSharedPreferences("LovRUserSettings", 0)
.getString("firstName", "Username"));
}else{
elementText.setText(textValue);
}
ImageView elementImage = (ImageView)rowView.findViewById(R.id.element_icon);
switch (position){
case 2:
elementImage.setImageResource(R.drawable.search);
break;
case 3:
elementImage.setImageResource(R.drawable.facebook_friends);
break;
case 4:
elementImage.setImageResource(R.drawable.flirts_history);
break;
case 5:
elementImage.setImageResource(R.drawable.premium);
break;
case 7:
elementImage.setImageResource(R.drawable.settings);
break;
case 8:
elementImage.setImageResource(R.drawable.share_app);
break;
case 9:
elementImage.setImageResource(R.drawable.cgu);
break;
}
}
return rowView;
}
}
In this code, there's an object called userBar. You don't really need to pay attention to this but if you're interested, it's another menu element, using a specific layout file instead of the one I use for regular menu elements. It's a way to demonstrate that you can add whatever kind of specific layout anywhere you want, just by reading your strings.
The main point here is in the way the code searches for separators, the strings with the -sep- prefix. Once one is found, the prefix is removed, and the matching layout is attributed to the separator.
Aight, that's what i've found. After this, you'll have to find your own way to add click listeners. Mines are implemented in the DrawerLayout.setOnCliclListener which basically does the job the exact same way the Google's documentation says. But you can also use setOnclickListenerto your view as you add them, and use an XML file where you can set your own onClick attributes...
Hope it will help =)

Different layouts in a viewpager

I am trying to do something like the android market to show products from different categories. I have implemented that behavior with this library, and it's all running good.
What I want to do now is to have a list view in the page of the categories, and in each one of the others a grid view. Of course, each one of them will have different sources of data.
How can I achieve that ? Does it have anything to do with adapters?
I have find one Very good Example you can find that on this site
https://github.com/astuetz/ViewPagerExtensions
Else hope this code will be Helpful to you.
#Override
public Object instantiateItem(View collection, int position) {
View v = new View(PatientView.this.getApplicationContext());
final LayoutInflater inflater = (LayoutInflater) PatientView.this
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
switch (position) {
case 0:
v = inflater.inflate(R.layout.patientp1,
(ViewGroup) null, false);
((Button) v.findViewById(R.id.pp1btnbck)).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
finish();
}
});
break;
case 1:
v = inflater.inflate(R.layout.patientp2, null, false
);
break;
default:
TextView tv = new TextView(PatientView.this.context);
tv.setText("Page " + position);
tv.setTextColor(Color.WHITE);
tv.setTextSize(30);
v = tv;
break;
}
((ViewPager) collection).addView(v, 0);
return v;
}
I think you want extend FragmentPagerAdapter, override getItem, and return the proper Fragment object (or ListFragment) depending on the index/position in the ViewPager.
In the layout xml for your Activity you should include a ViewPager (<android.support.v4.view.ViewPager>), and in your Activity onCreate use the setAdapter method of ViewPager to assign your FragmentPagerAdapter.

Create a ViewPager or equivalent WITH functionality in Android

I know this may sound like a terrible question to ask but I have been researching as much as I could to figure this out. I have an application that requires a view pager to scroll horizontally to display different views. Within each view, it needs functionality, for one view it could be just pressing a button, another view is required to download data from a server (for example, retrieving the latest Twitter feed) as well as other functionality. The main point is that within the View Pager, each view requires functionality.
My original idea was to follow this tutorial:
http://mobile.tutsplus.com/tutorials/android/android-user-interface-design-horizontal-view-paging/
However, this is just providing views which have no interaction. I have managed to implement this and add my layouts, however this is only solving half of the problem. It shows how to add basic operations within a comment such as a single button. I want each view to have its own activity which is capable of doing its own unique thing.
Here is what I originally had:
public class DashboardContainerActivity extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
//Set content view to the dashboard container xml view
setContentView(R.layout.dashboard_container);
//Create a new instance of my page adapter from below
MyPageAdapter adapter = new MyPageAdapter();
//Reference the view pager used in the dashboard container xml view
ViewPager myPager = (ViewPager) findViewById(R.id.dashboardpanelpager);
//set an adapter to the view pager
myPager.setAdapter(adapter);
//First panel to be shown when opened
myPager.setCurrentItem(3);
}
}
/*------------------------------------------------------*/
class MyPageAdapter extends PagerAdapter {
public int getCount() {
//Return 7 as there will be 7 panes in the dashboard
return 7;
}
public Object instantiateItem(View collection, int position) {
LayoutInflater inflater = (LayoutInflater) collection.getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = null;
switch (position) {
case 0:
v = inflater.inflate(R.layout.dashboard_social, null);
break;
case 1:
v = inflater.inflate(R.layout.dashboard_info, null);
//DISPLAY INFORMATION FROM SERVER AND DISPLAY HERE
break;
case 2:
v = inflater.inflate(R.layout.dashboard_allcourses, null);
//LIST OF COURSES
break;
case 3:
v = inflater.inflate(R.layout.dashboard_news, null);
//USE HTTP HERE FOR TWITTER FEED
break;
case 4:
v = inflater.inflate(R.layout.dashboard_mycourse, null);
//DOWNLOAD USER'S PERSONAL INFORMATION AND DISPLAY HERE
break;
case 5:
v = inflater.inflate(R.layout.dashboard_media, null);
//DISPLAY LATEST UPLOADED MULTIMEDIA
break;
case 6:
v = inflater.inflate(R.layout.dashboard_extras, null);
break;
}
((ViewPager) collection).addView(v, 0);
return v;
}
#Override
public void destroyItem(View arg0, int arg1, Object arg2) {
((ViewPager) arg0).removeView((View) arg2);
}
#Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == ((View) arg1);
}
#Override
public Parcelable saveState() {
return null;
}
}
I have separate activities for each layout added to the ViewPager but I am guessing that these activities cannot be added into the ViewPager instead of just the layouts.
I have read something about fragments, but I am not sure whether that's compatible with API level 8, apparently this is targeted at Honeycomb and Ice Cream Sandwich.
It's not possible to have an Activity as part of a ViewPager, however there is no reason why you can't add the functionality you describe to each page in your ViewPager. To assign interaction or events to components in each view just add the correct listeners in instantiateItem() in each case statement:
case 0:
v = inflater.inflate(R.layout.dashboard_social, null);
Button myButton = (Button) v.findViewById(R.id.name_of_button_in_social_dashboard);
myButton.setOnClickListener(...);
break;
For any other interactions, like getting the http requests for the twitter feed, just execute those as part of your main activity (something like http requests should be done in a background thread of course). When you want to update the UI in the twitter page, just use ViewPager.getChildAt(3) to fetch the child element. Think of your Activity as just a big layout with 7 children views that are all available at once (but the user will only see them as they swipe).
With all that said, a better design patter might be to use Fragments with a FragmentPagerAdapter backing your ViewPager. This allows better logical breakdown of the various pages into different classes - Fragments also provide other uses like being able to load multiple on-screen at once for larger screen layouts (tablets).
Like ViewPager, Fragments are available all the way back to API Level 4 via the support library (see Fragment). So you don't need to worry about backward compatibility.

Displaying multiple xml views w/o fragments

In my app the user spins a carousel. On the selected Item I need to display a separate xml view for each item. The carousel is visibile at all time at the bottom with the view visible in the top half. I think that there is a better way than to use fragments. Any ideas? The following code is not functional as of now but I think an inflator may be the way to go but to get it done is troubling me. After case0 there is case1-case5.
carousel.setOnItemSelectedListener(new OnItemSelectedListener(){
public void onItemSelected(CarouselAdapter<?> parent, View view,
int position, long id) {
switch(position){
case 0:
final View firstview;
LayoutInflater inflater = (LayoutInflater) getBaseContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
firstview = inflater.inflate(R.layout.selected_item, null);
break;
case 1:
In case anyone else runs into this problem I solved it:
LayoutInflater inflater = (LayoutInflater) CarouselActivity.this.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
LinearLayout inflateView = (LinearLayout) findViewById( R.id.InflateParent );
View nextView = null;
switch(position){
case 0:
System.out.println("Case 0");
inflateView.removeAllViews();
nextView = inflater.inflate( R.layout.nextview, null );
inflateView.addView(nextView);

Android: Switch statement used with OnItemClickListener() is always choosing last case regardless of selected item

Having a hard time figuring out the best way to go about this. What I've got going on is a gallery view loaded with images, with a text view just beneath it. I would like to fill the contents of the textview based upon which image is clicked. I followed the standard GalleryView tutorial where it has you create a custom ImageAdapter class which extends the BaseAdapter class. In doing so, I created an OnItemClickListener for the galleryview, and I assumed the next logical step would be to create a switch statement to figure out what to put in the text view.
So I eventually figured out that I should probably be itererating over the gallery items as opposed to the parameters passed to the onitemclicklistener() method. The problem is now, no matter what item is clicked, the output to the desired text view is always as if the last item was clicked. I commented out the 'case 2', and it then began to always take case 1. What would be causing the switch statement to 'default' to the last case coded even though I have not defined a default case?
Additionally, I'm seeing conflicting stuff regarding the switch statement in terms of looping. It should loop on its own, yes? If so I imagine it probably is, but since it always selects case 2, I'm not realizing that the output of the text should be changing? Is my switch statement all messed up? do I need to include some sort of loop? What am I doing wrong here?
Custom ImageAdapter class:
public class ImageAdapter extends BaseAdapter
{
private Context context;
private int itemBackground;
public ImageAdapter(Context c)
{
context = c;
//---setting the style---
TypedArray a = obtainStyledAttributes(R.styleable.Gallery1);
itemBackground = a.getResourceId(
R.styleable.Gallery1_android_galleryItemBackground, 0);
a.recycle();
}
//---returns the number of images---
public int getCount() {
return imageIDs.length;
}
//---returns the ID of an item---
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
//---returns an ImageView view---
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView = new ImageView(context);
imageView.setImageResource(imageIDs[position]);
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
imageView.setLayoutParams(new Gallery.LayoutParams(150, 120));
imageView.setBackgroundResource(itemBackground);
return imageView;
}
}
}
And here is the code I'm using to create the galleryview and the onitemclicklistener:
Gallery gallery = (Gallery) findViewById(R.id.top_gallery);
gallery.setAdapter(new ImageAdapter(this));
gallery.setOnItemClickListener(new OnItemClickListener()
{
public void onItemClick(AdapterView parent,
View v, int position, long id)
{
TextView tView = (TextView) findViewById(R.id.cat_desc);
switch(gallery.getSelectedItemPosition())
{
case 0:
tView.setText("Option1");
case 1:
tView.setText("Option2");
case 2:
tView.setText("Option3");
}
}
You're lacking break's in case statement and code gets executed in linear way. That's why the last is always selected.
You need break; in your case, else it will fall through. Try:
case 0 : tView.setText("Option1"); break;
You are missing the breaks;
switch(gallery.getSelectedItemPosition())
{
case 0:
tView.setText("Option1");
break;
case 1:
tView.setText("Option2");
break;
case 2:
tView.setText("Option3");
break;
}

Categories

Resources