IMPORTANT: Per accedir als fitxer de subversion: http://acacha.org/svn (sense password). Poc a poc s'aniran migrant els enllaços. Encara però funciona el subversion de la farga però no se sap fins quan... (usuari: prova i la paraula de pas 123456)

Contingut

Conceptes

Components principals

Allapsscren.png

Ui overview recents.png

Ui overview system ui.png

  • Status Bar: Displays pending notifications on the left and status, such as time, battery level, or signal strength, on the right. Swipe down from the status bar to show notification details.
  • Navigation Bar:
  • Combined Bar: On tablet form factors the status and navigation bars are combined into a single bar at the bottom of the screen.


Notificacions

Recursos:

Exemple aplicació comuna

Una aplicació android típica té els següents apartats:

  • Main Action Bar: és el centre de l'aplicació on apareixen les comandes i el control bàsic de l'aplicació. Inclou elements de navegació per l'aplicació (navegació per la jerarquia de vistes) i també mostra les accions més importants.
  • View Control: Allows users to switch between the different views that your app provides. Views typically consist of different arrangements of your data or different functional aspects of your app.
  • Content Area: The space where the content of your app is displayed.
  • Split Action Bar: Split action bars provide a way to distribute actions across additional bars located below the main action bar or at the bottom of the screen. In this example, a split action bar moves important actions that won't fit in the main bar to the bottom.


Recursos:

Screen densities

Vegeu també Screen densities

Classes. Android UI toolkit

El paquet Java.

android.view [1]

Proveix les classes i interfícies java encarregades de la interfície gràfica Android i és l'encarregada de gestionar el layot de la pantalla amb la que interactua l'usuari. En alguns casos també es fa referencia a aquest paquet, conjuntament amb:

android.widget [2]

com a Android UI toolkit.


Views (Vistes)

TODO: viewgroup.png

Tots els elements d'interfície a Android es construeixen utilitzant els objecte View o ViewGroup.

Android proporciona una col·lecció de Vistes i grups de vistes per defecte que permeten implementar els controls més habituals com Botons o camps de text (Text Fields)

Recursos:

ViewList

L'objecte android.widget.ListView [3] té la següent jerarquia:

java.lang.Object
  ↳ 	android.view.Viewandroid.view.ViewGroupandroid.widget.AdapterView<T extends android.widget.Adapter>
 	  	  	   ↳ 	android.widget.AbsListView
 	  	  	  	   ↳ 	android.widget.ListView

Per tant podem veure com es tracta d'un Widget Android, i també com és un conjunt de vistes o viewGroup i que a més és de tipus AdapterView, és a dir una llista que treballa amb Adaptadors.

Un exemple de layout XML amb una ViewList:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <ListView
        android:id="@+id/mylist"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
    </ListView>

</LinearLayout> 
Adapters
http://www.sgoliver.net/blog/interfaz-de-usuario-en-android-controles-de-seleccion-i/

Els adaptadors s'utilitzen per proveir de dades al objecte ListView (o si utilitzem fragments els ListFragment). També defineixen com es mostra cada fila a la ListView.

Vegeu imatge de la web [4]:

Adapter-16e1f75d957bbf1a8f093df67d165fcc.png
Custom_Base_adapter-8bd83ca2985afaddcd43e6e6d8fae32d.png

Els adaptadors s'assignen a ListView o ListFragment utilitzant el mètode:

setAdapter [5]

Un adaptador és una classe filla de:

BaseAdapter [6]

Android us proporcionar una sèrie de adaptadors per defecte com:

  • ArrayAdapter: permet crear adaptadors a partir de dades basades en l'estructura de dades array o java.util.List.
  • CursorAdapter: La classe SimpleCursorAdapter s'utilitza per fer llistes a partir de dades relacionades amb bases de dades.
  • TODO WrapperListAdapter: Sets the data behind this ListView. The adapter passed to this method may be wrapped by a WrapperListAdapter, depending on the ListView features currently in use. For instance, adding headers and/or footers will cause the adapter to be wrapped.
Adaptadors a mida

Per controlar la forma en que l'adaptador assigna les dades d'origen als diferents elements de la UI a mida d'un afila cal crear un implementació propia de Adapter (subclase de BaseAdapter).

El mètode que cal sobrescriure és:

getView()

Que és el que utilitza la ListView o el ListFragment per obtenir la vista de la fila. El root del layout. Exemple:

package de.vogella.android.listactivity;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class MySimpleArrayAdapter extends ArrayAdapter<String> {
  private final Context context;
  private final String[] values;

  public MySimpleArrayAdapter(Context context, String[] values) {
    super(context, R.layout.rowlayout, values);
    this.context = context;
    this.values = values;
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
    LayoutInflater inflater = (LayoutInflater) context
        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View rowView = inflater.inflate(R.layout.rowlayout, parent, false);
    TextView textView = (TextView) rowView.findViewById(R.id.label);
    ImageView imageView = (ImageView) rowView.findViewById(R.id.icon);
    textView.setText(values[position]);
    // Change the icon for Windows and iPhone
    String s = values[position];
    if (s.startsWith("iPhone")) {
      imageView.setImageResource(R.drawable.no);
    } else {
      imageView.setImageResource(R.drawable.ok);
    }

    return rowView;
  }
} 

Dins del mètode getView() podeu "inflar" un layout basat en XML i aleshores establir els valors de les vistes individuals de cada layour.

Per inflar un layout XML podeu utilitzar el servei del sistema anomenat:

LayoutInflator

Que està disponible a través de la Activitat o del mètode:

context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)

Els elements individuals del layout es poden trobar utilitzant findViewById()

Recursos:

Exemples
ArrayAdapter

Vegem un exemple de com utilitzar un array de valors per a omplir una llista:

ListView listView = (ListView) findViewById(R.id.mylist);
String[] values = new String[] { "Android", "iPhone", "WindowsMobile",
  "Blackberry", "WebOS", "Ubuntu", "Windows7", "Max OS X",
  "Linux", "OS/2" };

// Define a new Adapter
// First parameter - Context
// Second parameter - Layout for the row
// Third parameter - ID of the TextView to which the data is written
// Forth - the Array of data

ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
  android.R.layout.simple_list_item_1, android.R.id.text1, values);


// Assign adapter to ListView
listView.setAdapter(adapter); 

Un altre exemple similar amb imatges:

http://www.codelearn.org/android-tutorial/android-list-view

Vegeu:

Array_adapter-42a9ffe9f918f441ce8ff09ca288dacb.png

El més important és tenir en compte que:

android.R.layout.simple_list_item1

Consulteu android.R.layout

http://developer.android.com/reference/android/R.layout.html

és un recurs predefinit que ens proporciona la plataforma Android (no cal definir-lo en els nostres layouts, ja ve predefinit.)

Recursos:

ArrayAdapter (android.R.layout.simple_list_item2)

TODO

ArrayAdapter amb ListFragment
package de.vogella.android.fragments;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.app.ListFragment;

public class MyListFragment extends ListFragment {

  @Override
  public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    String[] values = new String[] { "Android", "iPhone", "WindowsMobile",
        "Blackberry", "WebOS", "Ubuntu", "Windows7", "Max OS X",
        "Linux", "OS/2" };
    ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(),
        android.R.layout.simple_list_item_1, values);
    setListAdapter(adapter);
  }

  @Override
  public void onListItemClick(ListView l, View v, int position, long id) {
    // Do something with the data

  }

} 
Exemple agafant les dades de la llista d'un XML strin-array resource
ArrayAdapter customitzat 1

Apartat CustomListItem:

http://www.codelearn.org/android-tutorial/android-list-view

Imatge:

list_item-83aff1328e47b603c9f0c638a3d2d9c3.png
ArrayAdapter customitzat 2

Volem fer una llista amb l'estil:

TODO: image
XC7SMdAbAx.png

El primer que cal fer és definir un objecte contenidor de les files:

package app.arsviator;

public class ABEntry {
    private String name;
    private String phoneNo;
    private int photo;
   
    public ABEntry(String _name, String _pn, int _photo) {
        this.name = _name;
        this.phoneNo = _pn;
        this.photo = _photo;
    }
   
    public String getName() {
        return name;
    }

    public String getPhoneNo() {
        return phoneNo;
    }

    public int getPhotoId() {
        return photo;
    }
}

Ara definim el layout d'una fila:

Xb2iSY0xm8.png

En XML ( /res/layout/entry.xml )

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:paddingTop="5px"
    android:paddingBottom="5px"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" >
  <ImageView android:id="@+id/ePhoto"
    android:layout_width="48px"
    android:layout_height="48px"
    android:src="@drawable/nophoto" />
  <LinearLayout android:orientation="vertical"
      android:paddingLeft="10px"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <TextView android:id="@+id/eName"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textSize="22sp" />
    <TextView android:id="@+id/ePhoneNo"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textSize="16sp" />
  </LinearLayout>
  <TextView android:id="@+id/eNull"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content" />
</LinearLayout>

I ara creem un objecte fill de ArrayAdapter i implemente getView:

private class ABArrayAdapter extends ArrayAdapter<ABEntry> {
        private ArrayList<ABEntry> items;
        private int rsrc;
       
        public ABArrayAdapter(Context ctx, int rsrcId, int txtId, ArrayList<ABEntry> data) {
            super(ctx, rsrcId, txtId, data);
            this.items = data;
            this.rsrc = rsrcId;
        }
       
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View v = convertView;
            if (v == null) {
                LayoutInflater li = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                v = li.inflate(rsrc, null);
            }
            ABEntry e = items.get(position);
            if (e != null) {
                ((TextView)v.findViewById(R.id.eName)).setText(e.getName());
                ((TextView)v.findViewById(R.id.ePhoneNo)).setText(e.getPhoneNo());
                if (e.getPhotoId() != -1) {
 ((ImageView)v.findViewById(R.id.ePhoto)).setImageResource(e.getPhotoId());               
                } else {
 ((ImageView)v.findViewById(R.id.ePhoto)).setImageResource(R.drawable.nophoto); 
                }
            }
            return v;
        }
    }
}

Ara el Listview seria:

package app.arsviator;

import java.util.ArrayList;

import android.app.AlertDialog;
import android.app.ListActivity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

public class CustomAA extends ListActivity {
    ArrayAdapter<ABEntry> abAdapter;
    final ArrayList<ABEntry> abList = new ArrayList<ABEntry>();
    Context ctx = this;
   
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
               
        ABEntry ne1 = new ABEntry("Mia","01034567890", R.drawable.photo1);
        abList.add(ne1);
        ABEntry ne2 = new ABEntry("Aki","01062954351", R.drawable.photo2);
        abList.add(ne2);
        ABEntry ne3 = new ABEntry("Snoopy","01091534510", -1);
        abList.add(ne3);
        ABEntry ne4 = new ABEntry("Jenny","01034964501", R.drawable.photo3);
        abList.add(ne4);
        ABEntry ne5 = new ABEntry("Kim","01043956103", -1);
        abList.add(ne5);

        abAdapter = new ABArrayAdapter(this, R.layout.entry, R.id.eName, abList);
        setListAdapter(abAdapter);       
    }
   
    public void onListItemClick(ListView parent, View v, int pos, long id) {
        final int index = pos;
        final ABEntry ent = abAdapter.getItem(pos);
        final String pn = ent.getPhoneNo();
        final int _photo = ent.getPhotoId()!=-1?ent.getPhotoId():R.drawable.nophoto;       
       
        new AlertDialog.Builder(this).setTitle(ent.getName())
        .setMessage(pn)
        .setIcon(ent.getPhotoId())
        .setNegativeButton("Delete", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dlg, int sumthin) {
                abAdapter.remove(ent);
                abAdapter.notifyDataSetChanged();
            }           
        })
        .setNeutralButton("Call", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dlg, int sumthin) {
                    Intent i = new Intent(Intent.ACTION_CALL, Uri.parse("tel:"+pn));
                    startActivity(i);               
                }
        })
        .show();
    }
   
    private class ABArrayAdapter extends ArrayAdapter<ABEntry> {
        private ArrayList<ABEntry> items;
        private int rsrc;
       
        public ABArrayAdapter(Context ctx, int rsrcId, int txtId, ArrayList<ABEntry> data) {
            super(ctx, rsrcId, txtId, data);
            this.items = data;
            this.rsrc = rsrcId;
        }
       
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View v = convertView;
            if (v == null) {
                LayoutInflater li = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                v = li.inflate(rsrc, null);
            }
            ABEntry e = items.get(position);
            if (e != null) {
                ((TextView)v.findViewById(R.id.eName)).setText(e.getName());
                ((TextView)v.findViewById(R.id.ePhoneNo)).setText(e.getPhoneNo());
                if (e.getPhotoId() != -1) {
 ((ImageView)v.findViewById(R.id.ePhoto)).setImageResource(e.getPhotoId());               
                } else {
 ((ImageView)v.findViewById(R.id.ePhoto)).setImageResource(R.drawable.nophoto);           
                }
            }
            return v;
        }
    }
}

Recursos

ArrayAdapter customitzat 3 utilitzant DataSource: JSON
GSON#ViewList

Recursos:

ImageListAdapter
public class ImageListAdapter extends BaseAdapter {
 
       private Context mContext;
 
       private LayoutInflater mLayoutInflater;                              
 
       private ArrayList<Entry> mEntries = new ArrayList<Entry>();          
 
       private final ImageDownloader mImageDownloader;                      
 
       public ImageListAdapter(Context context) {                           
          mContext = context;
          mLayoutInflater = (LayoutInflater) mContext
                   .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
          mImageDownloader = new ImageDownloader(context);
       }
 
       @Override
       public int getCount() {
          return mEntries.size();
       }
 
       @Override
       public Object getItem(int position) {
          return mEntries.get(position);
       }
 
       @Override
       public long getItemId(int position) {
          return position;
       }
 
       @Override
       public View getView(int position, View convertView,
             ViewGroup parent) {                                           
          RelativeLayout itemView;
          if (convertView == null) {                                       
             itemView = (RelativeLayout) mLayoutInflater.inflate(
                      R.layout.list_item, parent, false);
 
          } else {
             itemView = (RelativeLayout) convertView;
          }
 
          ImageView imageView = (ImageView)
             itemView.findViewById(R.id.listImage);                        
          TextView titleText = (TextView)
             itemView.findViewById(R.id.listTitle);                        
          TextView descriptionText = (TextView)
             itemView.findViewById(R.id.listDescription);                  
 
          String imageUrl = mEntries.get(position).getContent().getSrc();  
          mImageDownloader.download(imageUrl, imageView);                  
 
          String title = mEntries.get(position).getTitle().get$t();
          titleText.setText(title);
          String description =
             mEntries.get(position).getSummary().get$t();
          if (description.trim().length() == 0) {
             description = "Sorry, no description for this image.";
          }
          descriptionText.setText(description);
 
          return itemView;
       }
 
       public void upDateEntries(ArrayList<Entry> entries) {
          mEntries = entries;
          notifyDataSetChanged();
       }

Widgets

El paquet Java:

android.widget

conté element de la interfície gràfica (aka widgets) que s'utilitzen a la pantalla de l'aplicació. Android proveix una sèrie de widgets per defecte, però a més, és possible crear els nostres propis widgets, des de zero o a partir de widgets ja existents.

Recursos:

Custom Widget

TODO

To create your own widget, extend View or a subclass. To use your widget in layout XML, there are two additional files for you to create. Here is a list of files you'll need to create to implement a custom widget:

Java implementation file - This is the file that implements the behavior of the widget. If you can instantiate the object from layout XML, you will also have to code a constructor that retrieves all the attribute values from the layout XML file. XML definition file - An XML file in res/values/ that defines the XML element used to instantiate your widget, and the attributes that it supports. Other applications will use this element and attributes in their in another in their layout XML. Layout XML [optional]- An optional XML file inside res/layout/ that describes the layout of your widget. You could also do this in code in your Java file.

ApiDemos sample application has an example of creating a custom layout XML tag, LabelView. See the following files that demonstrate implementing and using a custom widget:

   LabelView.java - The implementation file
   res/values/attrs.xml - Definition file
   res/layout/custom_view_1.xml - Layout file

Recursos:

UI Layouts

Introducció

La interfície d'usuari es defineix sempre com una jerarquia d'objectes View o ViewGroup tal i com es mostra a la figura:

viewgroup.png

Cada grup de vistes és un contenidor invisible que organitzar les vistres filla i les vistes filla són nodes final fulla de la jerarquia que defineixen input controls o altres widgets que pinten part de la UI de l'aplicació.

Per declarar el layout es pot fer per codi instanciant objectes de tipus View i començar a crear l'arbre o es pot fer en temps de compilació utilitzant un fitxer XML. XML ofereix una estructura llegible per un humà de forma similar a un fitxer HTML.

El nom d'un element XML d'una vista sol coincidir amb el nom de la classe que el representa.

<TextView > --> textView class
<LinearLayout> --> LinearLayout view group.

Un exemple de layout vertical amb una text view i un boto:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="fill_parent" 
              android:layout_height="fill_parent"
              android:orientation="vertical" >
    <TextView android:id="@+id/text"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="I am a TextView" />
    <Button android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="I am a Button" />
</LinearLayout>

En temps de compilació es defineixen els objectes i Android en temps d'execució els posa disponibles per ser accessibles, adaptats i modificats en temps d'execució.

Com funcionen i com definir-los?

Un layout defineix la estructura visual de la interfície d'usuari (aka UI) d'una Activitat o un app widget Android.

Es poden definir/declarar els layouts de dos maneres:

  • XML: Android proporciona un vocabulary XML que es correspon amb les classes i subclasses relacionades amb la UI i que permet definir widgets i layouts. S'utilitzant un tipus específic de Recursos Android anomenats layouts. Vegeu el següent apartat per a més informació.
  • Runtime o codi Java: En temps d'execució es poden crear objectes View i View Group

NOTA: Crear layouts en Runtime no vol dir necessariament que siguin hardcoded. En alguns casos no tindrem més remei però podem igualment programar tenint en compte el Separation OF Concerns

Es poden combinar els dos mètodes si es creeu necessari i de fet és força natural i normal, per exemple, la part estàtica es defineix al XML i el codi s'encarrega de canviar l'estat de la interfície gràfica.

El plugin ADT d'Android ofereix un vista layout preview (Layout tab) que permet veure una espècie de WISIWIG, així no cal executar l'aplicació al mòbil per fer-se una idea de com serà el layout.

Imatge plugin adt: http://android-er.blogspot.com.es/2013/07/graphical-layout-editor-of-adt.html

També és útil l'eina Hierarchy Viewer, per tal de depurar els layouts, mostra els valors de les propietats dels layouts i els elements que contenen.

IMPORTANT: l'eina layoutopt permet analizar els layous de forma ràpida i eficient per tal de localitzar-hi problemes

L'avantatge clar d'utilitzar XML és que permet separar la presentació del codi. El layout es extern al codi de forma que es pot modificar sense haver de modificar el codi. Per exemple es poden crear diferents layouts per a diferents mides de pantalla, orientacions de pantalla, idiomes, etc. També es més fàcil d'entendre el layout i per tant més fàcil de depurar en busca d'errors.

En general el vocabulari XML dels layouts segueix força els noms i la estructura dels objectes Java que representen.

Recursos:

Layout Resource

Un layout resource és un Android App Resource que defineix la arquitectura de la UI d'una Activitat Android o un component de la UI.

Path del fitxer:

   res/layout/filename.xml

El filename s'utilitzarà com a resource ID

Resource reference, o com utilitzar-los o fer-ne referència:

In Java: R.layout.filename
In XML: @[package:]layout/filename 

La sintaxi és:

    <?xml version="1.0" encoding="utf-8"?>
    <ViewGroup xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@[+][package:]id/resource_name"
        android:layout_height=["dimension" | "fill_parent" | "wrap_content"]
        android:layout_width=["dimension" | "fill_parent" | "wrap_content"]
        [ViewGroup-specific attributes] >
        <View
            android:id="@[+][package:]id/resource_name"
            android:layout_height=["dimension" | "fill_parent" | "wrap_content"]
            android:layout_width=["dimension" | "fill_parent" | "wrap_content"]
            [View-specific attributes] >
            <requestFocus/>
        </View>
        <ViewGroup >
            <View />
        </ViewGroup>
        <include layout="@layout/layout_resource"/>
    </ViewGroup>

IMPORTANT: L'element root pot ser tant un ViewGroup o un View, o l'element <merge>, però com tot document XML ben format només pot haver-hi un element arrel i ha de contenir l'atribut xmlns:android que indica l'espai de noms Android

Recursos

Referència del fitxer XML layout

A:

podeu trobar la referència explicant les opcions del fitxer layout.xml.

Elements XML

ViewGroup

A container for other View elements. There are many different kinds of ViewGroup objects and each one lets you specify the layout of the child elements in different ways. Different kinds of ViewGroup objects include LinearLayout, RelativeLayout, and FrameLayout. You should not assume that any derivation of ViewGroup will accept nested Views. Some ViewGroups are implementations of the AdapterView class, which determines its children only from an Adapter.

Attributes:

  • android:id: Resource ID. A unique resource name for the element, which you can use to obtain a reference to the ViewGroup from your application. See more about the value for android:id below.
  • android:layout_height: Dimension or keyword. Required. The height for the group, as a dimension value (or dimension resource) or a keyword ("fill_parent" or "wrap_content"). See the valid values below.
  • android:layout_width: Dimension or keyword. Required. The width for the group, as a dimension value (or dimension resource) or a keyword ("fill_parent" or "wrap_content"). See the valid values below.

Molts més atributs són suportats però aquests són els bàsics. Per a tenir una referència consulteu:

http://developer.android.com/reference/android/view/ViewGroup.html
View

An individual UI component, generally referred to as a "widget". Different kinds of View objects include TextView, Button, and CheckBox.

       attributes:
       android:id
           Resource ID. A unique resource name for the element, which you can use to obtain a reference to the View from your application. See more about the value for android:id below. 
       android:layout_height
           Dimension or keyword. Required. The height for the element, as a dimension value (or dimension resource) or a keyword ("fill_parent" or "wrap_content"). See the valid values below. 
       android:layout_width
           Dimension or keyword. Required. The width for the element, as a dimension value (or dimension resource) or a keyword ("fill_parent" or "wrap_content"). See the valid values below. 

More attributes are supported by the View base class, and many more are supported by each implementation of View. Read Layouts for more information. For a reference of all available attributes, see the corresponding reference documentation (for example, the TextView XML attributes).

requestFocus

Any element representing a View object can include this empty element, which gives it's parent initial focus on the screen. You can have only one of these elements per file.

include

Includes a layout file into this layout.

attributes:

  • layout: Layout resource. Required. Reference to a layout resource.
  • android:id: Resource ID. Overrides the ID given to the root view in the included layout.
  • android:layout_height: Dimension or keyword. Overrides the height given to the root view in the included layout. Only effective if android:layout_width is also declared.
  • android:layout_width: Dimension or keyword. Overrides the width given to the root view in the included layout. Only effective if android:layout_height is also declared. You can include any other layout attributes in the <include> that are supported by the root element in the included layout and they will override those defined in the root element.

Caution: If you want to override layout attributes using the <include> tag, you must override both android:layout_height and android:layout_width in order for other layout attributes to take effect.

Another way to include a layout is to use ViewStub. It is a lightweight View that consumes no layout space until you explicitly inflate it, at which point, it includes a layout file defined by its android:layout attribute. For more information about using ViewStub, read Loading Views On Demand.

merge

An alternative root element that is not drawn in the layout hierarchy. Using this as the root element is useful when you know that this layout will be placed into a layout that already contains the appropriate parent View to contain the children of the <merge> element. This is particularly useful when you plan to include this layout in another layout file using <include> and this layout doesn't require a different ViewGroup container. For more information about merging layouts, read Re-using Layouts with <include/>.

   Value for android:id

For the ID value, you should usually use this syntax form: "@+id/name". The plus symbol, +, indicates that this is a new resource ID and the aapt tool will create a new resource integer in the R.java class, if it doesn't already exist. For example:

   <TextView android:id="@+id/nameTextbox"/>
   The nameTextbox name is now a resource ID attached to this element. You can then refer to the TextView to which the ID is associated in Java:
   findViewById(R.id.nameTextbox);
   This code returns the TextView object.
   However, if you have already defined an ID resource (and it is not already used), then you can apply that ID to a View element by excluding the plus symbol in the android:id value.
   Value for android:layout_height and android:layout_width:
   The height and width value can be expressed using any of the dimension units supported by Android (px, dp, sp, pt, in, mm) or with the following keywords:
   Value	Description
   match_parent 	Sets the dimension to match that of the parent element. Added in API Level 8 to deprecate fill_parent.
   fill_parent 	Sets the dimension to match that of the parent element.
   wrap_content 	Sets the dimension only to the size required to fit the content of this element.

Carregar el recurs XML layout des del codi Java

Al compilar l'aplicació el sistema automàticament (utilitzant TODO) "compila" els fitxers layout XML i crea un recurs de tipus Vista

S'utilitza el mètode callback onCreate:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_layout);
}

On R.layout.main_layout és una constant de tipus enter (Integer) amb el resource ID del recurs de tipus layout.

Vegeu l'apartat Cicle de vida Activitats Android per a més informació sobre els callbacks o mètodes esdeveniment de les Activitats.

Recursos:

Programació de layouts

Recursos:

Common Layout Objects i models de layout

Recursos:

Estàtics: LinearLayout, Relativelayou, WebView

  • LinearLayout. Atenció que té fills amb layouts més específics, per exemple table layout:

Recursos:

Dinàmics amb adaptadors (AdapterViews)

Consulteu l'api per tal de veure més exemples de vistes amb adaptador:

http://developer.android.com/reference/android/widget/AdapterView.html

Recursos:

ScrollView

TODO

Tutorials i exemples

Llista:

AbsoluteLayout:

Exemple vista de login (Linear layout):

AbsoluteLayout:

Table layout:

Altres:

Exemple avançat:

Menús

Els menús són un component d'interfície d'usuari molt comuns en molts tipus d'aplicacions. Android proporciona una API de menús que permet presentar accions d'usuari d'una forma familiar i consistent. Els menús es gestionen principalment a partir de la Vista Android:

 android.view.Menu

Des de la versió Android 3.0 (API level 11), ja no és necessari proveir d'un botó de menú dedicat. Cal tenir en compte que a més s'imposa el paradigma de disseny basat en Action Bar. Ja no és necessari proveir d'un menú amb totes les opcions sinó que es poden destacar les opcions de menú més importants posant-les a l'action bar.


Els menús d'accions es poden veure com una col·lecció Java, és a dir un grup d'objectes. Cada objecte del grup s'anomena menu item. Els menús tenen les accions més importants d'una activitat android: buscar, configuració, crear un email, etc...

Per mostrar el menú a l'usuari tenim dos opcions:

  • Android 2.3 o anterior: cal prémer el botó de menú
  • Android 3.0 o superior: El menú d'opcions es mostra en dos parts:
  • On-screen actions: Són les opcions de menú (menu items) que apareixen a l'Action Bar. Representen les accions més importants.
  • Overflow options: conté els ítems de menú secundaris. El boto de menú es considera deprecated

Hi ha diferents tipus de menú:

Definir els menús XML:

Per a tots els tipus de menú, la definició del menú es realitzar mitjançant un fitxer XML. Això permet evitar escriure en el codi gran parts dels menus. Altres avantatges són:

  • És més fàcil de visualitzar la estructura del menú.
  • Separation of concerns. Es separa el contingut del menú del codi
  • Es poden crear configuracions de menú alternatives per a diferents versiones, mides de pantalla, etc...

S'utilitza el concepte inflar (inflate menu) per referir-se a l'acció de carregar un menú definit en un XML en un objecte de tipus menu dins la nostra Activitat o Fragment

Els menús són per tant un tipus de Recurs Android que es defineixen a la carpeta:

res/menu/

Els elements XML vàlids són els següents:

  • <menu>: Defineix un Menu que no és res més que un contenidor d'ítems. Ha de ser l'element arrel de fitxer XML. Pot tenir com a fils un o més elements <item> i <group>.
  • <item>: Crea un MenuItem] que representa un entrada simple de menú. Pot tenir submenus (altres elements <menu> anidats)
  • <group>: és un contenidor opcional i invisible d'elements <item>. http://developer.android.com/guide/topics/ui/menus.html#groups

Vegem un exemple de fitxer menu.xml:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/new_game"
          android:icon="@drawable/ic_new_game"
          android:title="@string/new_game"
          android:showAsAction="ifRoom"/>
    <item android:id="@+id/help"
          android:icon="@drawable/ic_help"
          android:title="@string/help" />
</menu>

L'element <item> suporta múltiples atributs, a l'exemple:

  • android:id: Un resource ID que identifica de forma unívoca el ítem de menú.
  • android:icon: una referència a un drawable que s'utilitzarà com a icona del ítem de menu.
  • android:title: una referència a un recurs de tipus string que s'utilitza com a títol.
  • android:showAsAction: Indica quan l'opció de menú ha d'aparèixer o no al Action Bar. Normalment s'utilitza android:showAsAction="ifRoom", és a dir es posa l'acció al Action Bar si hi ha espai.

Podeu consultar tota la resta d'atributs a:

http://developer.android.com/reference/android/view/Menu.html
http://developer.android.com/guide/topics/resources/menu-resource.html

Es possible definir submenus:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/file"
          android:title="@string/file" >
        <!-- "file" submenu -->
        <menu>
            <item android:id="@+id/create_new"
                  android:title="@string/create_new" />
            <item android:id="@+id/open"
                  android:title="@string/open" />
        </menu>
    </item>
</menu>

Crear menús

Per tal d'utilitzar el menu en una activitat cal inflar (inflate) el recurs de menú amb:

MenuInflater.inflate()

Vegem alguns exemples:

Per a crear menús principals, el primer es tenir en compte la frontera que marca l'API 10 (Abans de 3.0).

Vegeu un exemple de menú per a una API 10 o inferior:

options_menu.png

És el típic menú de 6 items, si hi ha més de sis ítems es posen al submenu overflow de forma automàtica.

Amb Android 3.0 (API level 11) o superior s'utilitza l'Action Bar. http://developer.android.com/guide/topics/ui/actionbar.html

NOTA: Inclús per a aplicacions en versions inferiors a la 2.0 es pot simular el Action Bar. Vegeu http://developer.android.com/resources/samples/ActionBarCompat/index.html

Es pot utilitzar tant en objectes Activity (o subclasses Activity) com en Fragments.

NOTA: If both your activity and fragment declare items for the options menu, they are combined in the UI. The activity's items appear first, followed by those of each fragment in the order in which each fragment is added to the activity. If necessary, you can re-order the menu items with the android:orderInCategory attribute in each item you need to move

Per especificar el menú d'una activitat cal sobrescriure el mètode:

onCreateOptionsMenu()

consulteu:

http://developer.android.com/reference/android/app/Activity.html#onCreateOptionsMenu%28android.view.Menu%29

Dins es fa normalment el inflate. Vegem un exemple:

 
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.game_menu, menu);
    return true;
}

de forma dinàmica es poden afegir ítems amb:

add()

O obtenir ítems amb:

findItem()

tots els detalls al API de MenuItem:

http://developer.android.com/reference/android/view/MenuItem.html

NOTA: Per a la versió 2.3.x o inferior el sistema crida a onCreateOptionsMenu() al prémer el boto de menú. A la versió 3.0 o superior al mostrar l'activitat per tal que es vegin to create the options menu when the user opens the menu for the first time. If you've developed for Android 3.0 o superior es crida al iniciar l'activitat

Controlant els esdeveniments de clic:

Quan un usuari selecciona un menu item aleshores el sistema crida al mètode:

onOptionsItemSelected()

Aquest mètode passa el MenuItem seleccionat i el podeu identificar amb:

getItemId()

que retorna el resource ID del ítem de menu.

Un exemple:

 
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle item selection
    switch (item.getItemId()) {
        case R.id.new_game:
            newGame();
            return true;
        case R.id.help:
            showHelp();
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}

Sempre cal tornar:

true

quan l'acció es duu a terme correctament. .

TODO:

If your activity includes fragments, the system first calls onOptionsItemSelected() for the activity then for each fragment (in the order each fragment was added) 
until one returns true or all fragments have been called.

NOTA: Es pot utilitzar també el XML utilitzant l'atribut android:onClick

Una recomanació per compartir el mateix menú entre diferents activitats es tenir una classe Activitat pare de totes que defineixi les opcions de menú comunes a

onCreateOptionsMenu()

i

onOptionsItemSelected()

Es crida al pare amb:

super.onCreateOptionsMenu(menu)

i s'afegeixen opcions amb:

menu.add()

Es pot sobrescriure el comportament d'un item de menú concret sobrescrivint el mètode.


Changing menu items at runtime

After the system calls onCreateOptionsMenu(), it retains an instance of the Menu you populate and will not call onCreateOptionsMenu() again unless the menu is invalidated for some reason. However, you should use onCreateOptionsMenu() only to create the initial menu state and not to make changes during the activity lifecycle.

If you want to modify the options menu based on events that occur during the activity lifecycle, you can do so in the onPrepareOptionsMenu() method. This method passes you the Menu object as it currently exists so you can modify it, such as add, remove, or disable items. (Fragments also provide an onPrepareOptionsMenu() callback.)

Note: You should never change items in the options menu based on the View currently in focus. When in touch mode (when the user is not using a trackball or d-pad), views cannot take focus, so you should never use focus as the basis for modifying items in the options menu. If you want to provide menu items that are context-sensitive to a View, use a Context Menu.

Creant menús contextuals:

Figure 3. Screenshots of a floating context menu (left) and the contextual action bar (right).

A contextual menu offers actions that affect a specific item or context frame in the UI. You can provide a context menu for any view, but they are most often used for items in a ListView, GridView, or other view collections in which the user can perform direct actions on each item.

There are two ways to provide contextual actions:

   In a floating context menu. A menu appears as a floating list of menu items (similar to a dialog) when the user performs a long-click (press and hold) on a view that declares support for a context menu. Users can perform a contextual action on one item at a time.
   In the contextual action mode. This mode is a system implementation of ActionMode that displays a contextual action bar at the top of the screen with action items that affect the selected item(s). When this mode is active, users can perform an action on multiple items at once (if your app allows it).

Note: The contextual action mode is available on Android 3.0 (API level 11) and higher and is the preferred technique for displaying contextual actions when available. If your app supports versions lower than 3.0 then you should fall back to a floating context menu on those devices. Creating a floating context menu

To provide a floating context menu:

   Register the View to which the context menu should be associated by calling registerForContextMenu() and pass it the View.
   If your activity uses a ListView or GridView and you want each item to provide the same context menu, register all items for a context menu by passing the ListView or GridView to registerForContextMenu().
   Implement the onCreateContextMenu() method in your Activity or Fragment.
   When the registered view receives a long-click event, the system calls your onCreateContextMenu() method. This is where you define the menu items, usually by inflating a menu resource. For example:
   @Override
   public void onCreateContextMenu(ContextMenu menu, View v,
                                   ContextMenuInfo menuInfo) {
       super.onCreateContextMenu(menu, v, menuInfo);
       MenuInflater inflater = getMenuInflater();
       inflater.inflate(R.menu.context_menu, menu);
   }
   MenuInflater allows you to inflate the context menu from a menu resource. The callback method parameters include the View that the user selected and a ContextMenu.ContextMenuInfo object that provides additional information about the item selected. If your activity has several views that each provide a different context menu, you might use these parameters to determine which context menu to inflate.
   Implement onContextItemSelected().
   When the user selects a menu item, the system calls this method so you can perform the appropriate action. For example:
   @Override
   public boolean onContextItemSelected(MenuItem item) {
       AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
       switch (item.getItemId()) {
           case R.id.edit:
               editNote(info.id);
               return true;
           case R.id.delete:
               deleteNote(info.id);
               return true;
           default:
               return super.onContextItemSelected(item);
       }
   }
   The getItemId() method queries the ID for the selected menu item, which you should assign to each menu item in XML using the android:id attribute, as shown in the section about Defining a Menu in XML.
   When you successfully handle a menu item, return true. If you don't handle the menu item, you should pass the menu item to the superclass implementation. If your activity includes fragments, the activity receives this callback first. By calling the superclass when unhandled, the system passes the event to the respective callback method in each fragment, one at a time (in the order each fragment was added) until true or false is returned. (The default implementation for Activity and android.app.Fragment return false, so you should always call the superclass when unhandled.)

Contextual action mode

The contextual action mode is a system implementation of ActionMode that focuses user interaction toward performing contextual actions. When a user enables this mode by selecting an item, a contextual action bar appears at the top of the screen to present actions the user can perform on the currently selected item(s). While this mode is enabled, the user can select multiple items (if you allow it), deselect items, and continue to navigate within the activity (as much as you're willing to allow). The action mode is disabled and the contextual action bar disappears when the user deselects all items, presses the BACK button, or selects the Done action on the left side of the bar.

Note: The contextual action bar is not necessarily associated with the action bar. They operate independently, even though the contextual action bar visually overtakes the action bar position.

If you're developing for Android 3.0 (API level 11) or higher, you should usually use the contextual action mode to present contextual actions, instead of the floating context menu.

For views that provide contextual actions, you should usually invoke the contextual action mode upon one of two events (or both):

   The user performs a long-click on the view.
   The user selects a checkbox or similar UI component within the view.

How your application invokes the contextual action mode and defines the behavior for each action depends on your design. There are basically two designs:

   For contextual actions on individual, arbitrary views.
   For batch contextual actions on groups of items in a ListView or GridView (allowing the user to select multiple items and perform an action on them all).

The following sections describe the setup required for each scenario. Enabling the contextual action mode for individual views

If you want to invoke the contextual action mode only when the user selects specific views, you should:

   Implement the ActionMode.Callback interface. In its callback methods, you can specify the actions for the contextual action bar, respond to click events on action items, and handle other lifecycle events for the action mode.
   Call startActionMode() when you want to show the bar (such as when the user long-clicks the view).

For example:

   Implement the ActionMode.Callback interface:
   private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
       // Called when the action mode is created; startActionMode() was called
       @Override
       public boolean onCreateActionMode(ActionMode mode, Menu menu) {
           // Inflate a menu resource providing context menu items
           MenuInflater inflater = mode.getMenuInflater();
           inflater.inflate(R.menu.context_menu, menu);
           return true;
       }
       // Called each time the action mode is shown. Always called after onCreateActionMode, but
       // may be called multiple times if the mode is invalidated.
       @Override
       public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
           return false; // Return false if nothing is done
       }
       // Called when the user selects a contextual menu item
       @Override
       public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
           switch (item.getItemId()) {
               case R.id.menu_share:
                   shareCurrentItem();
                   mode.finish(); // Action picked, so close the CAB
                   return true;
               default:
                   return false;
           }
       }
       // Called when the user exits the action mode
       @Override
       public void onDestroyActionMode(ActionMode mode) {
           mActionMode = null;
       }
   };
   Notice that these event callbacks are almost exactly the same as the callbacks for the options menu, except each of these also pass the ActionMode object associated with the event. You can use ActionMode APIs to make various changes to the CAB, such as revise the title and subtitle with setTitle() and setSubtitle() (useful to indicate how many items are selected).
   Also notice that the above sample sets the mActionMode variable null when the action mode is destroyed. In the next step, you'll see how it's initialized and how saving the member variable in your activity or fragment can be useful.
   Call startActionMode() to enable the contextual action mode when appropriate, such as in response to a long-click on a View:
   someView.setOnLongClickListener(new View.OnLongClickListener() {
       // Called when the user long-clicks on someView
       public boolean onLongClick(View view) {
           if (mActionMode != null) {
               return false;
           }
           // Start the CAB using the ActionMode.Callback defined above
           mActionMode = getActivity().startActionMode(mActionModeCallback);
           view.setSelected(true);
           return true;
       }
   });
   When you call startActionMode(), the system returns the ActionMode created. By saving this in a member variable, you can make changes to the contextual action bar in response to other events. In the above sample, the ActionMode is used to ensure that the ActionMode instance is not recreated if it's already active, by checking whether the member is null before starting the action mode.

Enabling batch contextual actions in a ListView or GridView

If you have a collection of items in a ListView or GridView (or another extension of AbsListView) and want to allow users to perform batch actions, you should:

   Implement the AbsListView.MultiChoiceModeListener interface and set it for the view group with setMultiChoiceModeListener(). In the listener's callback methods, you can specify the actions for the contextual action bar, respond to click events on action items, and handle other callbacks inherited from the ActionMode.Callback interface.
   Call setChoiceMode() with the CHOICE_MODE_MULTIPLE_MODAL argument.

For example:

ListView listView = getListView(); listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); listView.setMultiChoiceModeListener(new MultiChoiceModeListener() {

   @Override
   public void onItemCheckedStateChanged(ActionMode mode, int position,
                                         long id, boolean checked) {
       // Here you can do something when items are selected/de-selected,
       // such as update the title in the CAB
   }
   @Override
   public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
       // Respond to clicks on the actions in the CAB
       switch (item.getItemId()) {
           case R.id.menu_delete:
               deleteSelectedItems();
               mode.finish(); // Action picked, so close the CAB
               return true;
           default:
               return false;
       }
   }
   @Override
   public boolean onCreateActionMode(ActionMode mode, Menu menu) {
       // Inflate the menu for the CAB
       MenuInflater inflater = mode.getMenuInflater();
       inflater.inflate(R.menu.context, menu);
       return true;
   }
   @Override
   public void onDestroyActionMode(ActionMode mode) {
       // Here you can make any necessary updates to the activity when
       // the CAB is removed. By default, selected items are deselected/unchecked.
   }
   @Override
   public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
       // Here you can perform updates to the CAB due to
       // an invalidate() request
       return false;
   }

});

That's it. Now when the user selects an item with a long-click, the system calls the onCreateActionMode() method and displays the contextual action bar with the specified actions. While the contextual action bar is visible, users can select additional items.

In some cases in which the contextual actions provide common action items, you might want to add a checkbox or a similar UI element that allows users to select items, because they might not discover the long-click behavior. When a user selects the checkbox, you can invoke the contextual action mode by setting the respective list item to the checked state with setItemChecked(). Creating a Popup Menu

Figure 4. A popup menu in the Gmail app, anchored to the overflow button at the top-right.

A PopupMenu is a modal menu anchored to a View. It appears below the anchor view if there is room, or above the view otherwise. It's useful for:

   Providing an overflow-style menu for actions that relate to specific content (such as Gmail's email headers, shown in figure 4).
   Note: This is not the same as a context menu, which is generally for actions that affect selected content. For actions that affect selected content, use the contextual action mode or floating context menu.
   Providing a second part of a command sentence (such as a button marked "Add" that produces a popup menu with different "Add" options).
   Providing a drop-down similar to Spinner that does not retain a persistent selection.

Note: PopupMenu is available with API level 11 and higher.

If you define your menu in XML, here's how you can show the popup menu:

   Instantate a PopupMenu with its constructor, which takes the current application Context and the View to which the menu should be anchored.
   Use MenuInflater to inflate your menu resource into the Menu object returned by PopupMenu.getMenu(). On API level 14 and above, you can use PopupMenu.inflate() instead.
   Call PopupMenu.show().

For example, here's a button with the android:onClick attribute that shows a popup menu:

<ImageButton

   android:layout_width="wrap_content" 
   android:layout_height="wrap_content" 
   android:src="@drawable/ic_overflow_holo_dark"
   android:contentDescription="@string/descr_overflow_button"
   android:onClick="showPopup" />

The activity can then show the popup menu like this:

public void showPopup(View v) {

   PopupMenu popup = new PopupMenu(this, v);
   MenuInflater inflater = popup.getMenuInflater();
   inflater.inflate(R.menu.actions, popup.getMenu());
   popup.show();

}

In API level 14 and higher, you can combine the two lines that inflate the menu with PopupMenu.inflate().

The menu is dismissed when the user selects an item or touches outside the menu area. You can listen for the dismiss event using PopupMenu.OnDismissListener. Handling click events

To perform an action when the user selects a menu item, you must implement the PopupMenu.OnMenuItemClickListener interface and register it with your PopupMenu by calling setOnMenuItemclickListener(). When the user selects an item, the system calls the onMenuItemClick() callback in your interface.

For example:

public void showMenu(View v) {

   PopupMenu popup = new PopupMenu(this, v);
   // This activity implements OnMenuItemClickListener
   popup.setOnMenuItemClickListener(this);
   popup.inflate(R.menu.actions);
   popup.show();

}

@Override public boolean onMenuItemClick(MenuItem item) {

   switch (item.getItemId()) {
       case R.id.archive:
           archive(item);
           return true;
       case R.id.delete:
           delete(item);
           return true;
       default:
           return false;
   }

}

Creating Menu Groups

A menu group is a collection of menu items that share certain traits. With a group, you can:

   Show or hide all items with setGroupVisible()
   Enable or disable all items with setGroupEnabled()
   Specify whether all items are checkable with setGroupCheckable()

You can create a group by nesting <item> elements inside a <group> element in your menu resource or by specifying a group ID with the the add() method.

Here's an example menu resource that includes a group:

<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android">

   <item android:id="@+id/menu_save"
         android:icon="@drawable/menu_save"
         android:title="@string/menu_save" />
   <group android:id="@+id/group_delete">
       <item android:id="@+id/menu_archive"
             android:title="@string/menu_archive" />
       <item android:id="@+id/menu_delete"
             android:title="@string/menu_delete" />
   </group>

</menu>

The items that are in the group appear at the same level as the first item—all three items in the menu are siblings. However, you can modify the traits of the two items in the group by referencing the group ID and using the methods listed above. The system will also never separate grouped items. For example, if you declare android:showAsAction="ifRoom" for each item, they will either both appear in the action bar or both appear in the action overflow. Using checkable menu items

Figure 5. Screenshot of a submenu with checkable items.

A menu can be useful as an interface for turning options on and off, using a checkbox for stand-alone options, or radio buttons for groups of mutually exclusive options. Figure 5 shows a submenu with items that are checkable with radio buttons.

Note: Menu items in the Icon Menu (from the options menu) cannot display a checkbox or radio button. If you choose to make items in the Icon Menu checkable, you must manually indicate the checked state by swapping the icon and/or text each time the state changes.

You can define the checkable behavior for individual menu items using the android:checkable attribute in the <item> element, or for an entire group with the android:checkableBehavior attribute in the <group> element. For example, all items in this menu group are checkable with a radio button:

<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android">

   <group android:checkableBehavior="single">
       <item android:id="@+id/red"
             android:title="@string/red" />
       <item android:id="@+id/blue"
             android:title="@string/blue" />
   </group>

</menu>

The android:checkableBehavior attribute accepts either:

single

   Only one item from the group can be checked (radio buttons)

all

   All items can be checked (checkboxes)

none

   No items are checkable

You can apply a default checked state to an item using the android:checked attribute in the <item> element and change it in code with the setChecked() method.

When a checkable item is selected, the system calls your respective item-selected callback method (such as onOptionsItemSelected()). It is here that you must set the state of the checkbox, because a checkbox or radio button does not change its state automatically. You can query the current state of the item (as it was before the user selected it) with isChecked() and then set the checked state with setChecked(). For example:

@Override public boolean onOptionsItemSelected(MenuItem item) {

   switch (item.getItemId()) {
       case R.id.vibrate:
       case R.id.dont_vibrate:
           if (item.isChecked()) item.setChecked(false);
           else item.setChecked(true);
           return true;
       default:
           return super.onOptionsItemSelected(item);
   }

}

If you don't set the checked state this way, then the visible state of the item (the checkbox or radio button) will not change when the user selects it. When you do set the state, the activity preserves the checked state of the item so that when the user opens the menu later, the checked state that you set is visible.

Note: Checkable menu items are intended to be used only on a per-session basis and not saved after the application is destroyed. If you have application settings that you would like to save for the user, you should store the data using Shared Preferences. Adding Menu Items Based on an Intent

Sometimes you'll want a menu item to launch an activity using an Intent (whether it's an activity in your application or another application). When you know the intent you want to use and have a specific menu item that should initiate the intent, you can execute the intent with startActivity() during the appropriate on-item-selected callback method (such as the onOptionsItemSelected() callback).

However, if you are not certain that the user's device contains an application that handles the intent, then adding a menu item that invokes it can result in a non-functioning menu item, because the intent might not resolve to an activity. To solve this, Android lets you dynamically add menu items to your menu when Android finds activities on the device that handle your intent.

To add menu items based on available activities that accept an intent:

   Define an intent with the category CATEGORY_ALTERNATIVE and/or CATEGORY_SELECTED_ALTERNATIVE, plus any other requirements.
   Call Menu.addIntentOptions(). Android then searches for any applications that can perform the intent and adds them to your menu.

If there are no applications installed that satisfy the intent, then no menu items are added.

Note: CATEGORY_SELECTED_ALTERNATIVE is used to handle the currently selected element on the screen. So, it should only be used when creating a Menu in onCreateContextMenu().

For example:

@Override public boolean onCreateOptionsMenu(Menu menu){

   super.onCreateOptionsMenu(menu);
   // Create an Intent that describes the requirements to fulfill, to be included
   // in our menu. The offering app must include a category value of Intent.CATEGORY_ALTERNATIVE.
   Intent intent = new Intent(null, dataUri);
   intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
   // Search and populate the menu with acceptable offering applications.
   menu.addIntentOptions(
        R.id.intent_group,  // Menu group to which new items will be added
        0,      // Unique item ID (none)
        0,      // Order for the items (none)
        this.getComponentName(),   // The current activity name
        null,   // Specific items to place first (none)
        intent, // Intent created above that describes our requirements
        0,      // Additional flags to control items (none)
        null);  // Array of MenuItems that correlate to specific items (none)
   return true;

}

For each activity found that provides an intent filter matching the intent defined, a menu item is added, using the value in the intent filter's android:label as the menu item title and the application icon as the menu item icon. The addIntentOptions() method returns the number of menu items added.

Note: When you call addIntentOptions(), it overrides any and all menu items by the menu group specified in the first argument. Allowing your activity to be added to other menus

You can also offer the services of your activity to other applications, so your application can be included in the menu of others (reverse the roles described above).

To be included in other application menus, you need to define an intent filter as usual, but be sure to include the CATEGORY_ALTERNATIVE and/or CATEGORY_SELECTED_ALTERNATIVE values for the intent filter category. For example:

<intent-filter label="@string/resize_image">

   ...
   <category android:name="android.intent.category.ALTERNATIVE" />
   <category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
   ...

</intent-filter>

Read more about writing intent filters in the Intents and Intent Filters document.

For a sample application using this technique, see the Note Pad sample code.

Context menu and contextual action mode

   A context menu is a floating menu that appears when the user performs a long-click on an element. It provides actions that affect the selected content or context frame.
   When developing for Android 3.0 and higher, you should instead use the contextual action mode to enable actions on selected content. This mode displays action items that affect the selected content in a bar at the top of the screen and allows the user to select multiple items.
   See the section about Creating Contextual Menus.

Popup menu

   A popup menu displays a list of items in a vertical list that's anchored to the view that invoked the menu. It's good for providing an overflow of actions that relate to specific content or to provide options for a second part of a command. Actions in a popup menu should not directly affect the corresponding content—that's what contextual actions are for. Rather, the popup menu is for extended actions that relate to regions of content in your activity.
   See the section about Creating a Popup Menu.


Recursos:

Formularis. Input controls

Temes

Els temes són el mecanisme que Android proporciona per oferir a l'usuari un estil consistent a una aplicació o activitat. El estil especifica les propietats visuals dels elements que conformem la interfície d'usuari, com el color, l'alçada, el padding (embolcall) o la mida de la font. Per tal de promocionar una cohesió més gran entre aplicacions a la plataforma, Android proporciona 3 temes de sistema (des de Ice Cream Sandwich)

Holo Light
Holo Dark
Holo Light amb barres d'acció fosques

Cal escollir el tema del sistema que sigui més apropiat a les necessitats i els criteris estètics de disseny de la vostra aplicació. També però és possible aplicar el vostre propi estil.

Estils

Un estil és una col·lecció de propietats que defineixen l'apariència i la forma d'una Vista (View) o Finestra Android. Permet especificar propietats com:

height, padding, font color, font size, background color...

Els estils es defineixen amb un recurs XML que es troba separat del XML que especifica el Layout.

NOTA: Els estils a Android segueixen la mateixa filosofia que les CSS, per que permeten separar el disseny del contingut

Un exemple, per al següent Layout:

 <TextView
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textColor="#00FF00"
    android:typeface="monospace"
    android:text="@string/hello" />

Amb estils es pot convertir en:

 <TextView 
    style="@style/CodeFont"
    android:text="@string/hello" />

En aquest cas tot lo referent a l'estil s'ha posat a un recurs Android anomenat CodeFont.

IMPORTANT: un tema és un estil que s'aplica a tota una activitat o una aplicació en comptes de a un item individual com a l'exemple anterior

Quan estil s'aplica com un tema, cada vista a la activitat o l'aplicació aplica les propietats d'estil que suporta segons l'estil indicat. Per exemple, es pot aplicar el estil CodeFont de l'exemple a una activitat i aleshores tot el text dins de l'activitat serà monoespai i verd.

Definir un estil

Per definir/crear un estil, cal crear i guardar un fitxer XML al directory:

/res/values/

El nom del fitxer XML es arbitrari, però ha de tenir l'extensió .xml.

NOTA: Com pdoeu veure no hi ha una carpeta especifica per al recurs de tipus estil...

vegem un exemple:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="CodeFont" parent="@android:style/TextAppearance.Medium">
        <item name="android:layout_width">fill_parent</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:textColor">#00FF00</item>
        <item name="android:typeface">monospace</item>
    </style>
</resources>

L'arrel XML sempre és resources. Per cada estil es defineix un element XML anomenat style.

Cada estil es convertit en un recurs Android en temps de compilació i es pot referenciar utilitzant el valor del atribut:

name

A l'exemple faríem referència utilitzant:

@style/CodeFont

Herència

L'herència s'utilitza per modificar i adaptar estils predefinits o aplicar petits canvis a un estil sense haver de tornar a definir-lo tot.

Un exemple de com com heretar l'apariència per defecte del text a Android i modificar-la:

    <style name="GreenText" parent="@android:style/TextAppearance">
        <item name="android:textColor">#00FF00</item>
    </style>

Si es vol heretar d'estils definits per un mateix i no pas pel sistema, NO s'ha d'utilitzar l'atribut parent.

 <style name="CodeFont.Red">
        <item name="android:textColor">#FF0000</item>
    </style>

Per utilitzar-lo es fa referència de la següent manera:

@style/CodeFont.Red.

Es pot fer tants cops com calgui:

 <style name="CodeFont.Red.Big">
        <item name="android:textSize">30sp</item>
    </style>

IMPORTANT: el punt només es pot utilitzar per a estils propis no per a estils de sistema. Aleshores cal utilitzar parent

Style Properties

El suc en els estils està en conèixer les propietats d'estil que es poden aplicar. El millor lloc per conèixer les propietats d'estil que es poden aplicar és la referència de la classe de la vista que esteu utilitzant. Un exemple (textView):

http://developer.android.com/reference/android/widget/TextView.html#lattrs

Un exemple concret sense estils:

<EditText
    android:inputType="number"
    ... />

I amb estils:

 <style name="Numbers">
  <item name="android:inputType">number</item>
  ...
 </style>

I per aplicar-lo:

 <EditText
    style="@style/Numbers"
    ... />

Per una referència de tots els estils disponibles cal consultar R.attr:

http://developer.android.com/reference/android/R.attr.html

Cal tenir en compte però que no tots els objectes de tipus vista suporten tots els atributs. En tot cas s'intenta aplicar una propietat d'estil no aplicable aleshores s'ignora.

IMPORTANT: algunes propietats d'estil només són aplicables als temes! Per exemple algunes propietats pode amagar el titol, la barra d'estat o canviar el fons de la finestra. Aquest tipus de propietats comencen per window a R.attr

Aplicar un estil a una vista

Vegem un exemple:

<TextView
    style="@style/CodeFont"
    android:text="@string/hello" />

NOTA: Fixeu-vos que l'atribut estil no utilitza el namespace Android, és a dir no utilitza el prefix android

Aplicar un tema a una activitat o aplicació

Es fa indicant-ho al fitxer:

AndroidManifest.xml

Cal editar l'etiqueta:

<application>

Per incloure l'atribut:

android:theme

Amb el nom de l'estil. Per exemple:

<application android:theme="@style/CustomTheme">

Si desitgeu que un tema s'apliqui a una activitat concreta aleshores cal afegir l'atribut:

android:theme

A l'etiqueta:

<activity>

De la mateixa forma que hi ha molts alt altres recursos built-in, també tenim estils per defecte que es poden utilitzar per tal de no tenir que definir-los un mateix. un exemple:

<activity android:theme="@android:style/Theme.Dialog">

Per fer que una activitat sembli un diàleg.

O per exemple per indicar un fons transparent, es pot utilitzar el tema Translucent:

<activity android:theme="@android:style/Theme.Translucent">

Es pot utilitzar l'herència per a partir d'un estil concret aplicar les vostres pròpies especificitats.

<color name="custom_theme_color">#b0b0ff</color>
<style name="CustomTheme" parent="android:Theme.Light">
    <item name="android:windowBackground">@color/custom_theme_color</item>
    <item name="android:colorBackground">@color/custom_theme_color</item>
</style>

Aleshores per utilitzar-lo:

<activity android:theme="@style/CustomTheme">

També es posible seleccionar un tema o un altre segons la versió d'Android:

<style name="LightThemeSelector" parent="android:Theme.Light">
    ...
</style>

Es pot utilitzar:

res/values-v11

com a tipus de recurs alternatiu

Exemples

Dashboard
styles.xml
<resources>
    <style name="ActionBarCompat">
        <item name="android:layout_width">fill_parent</item>
        <item name="android:layout_height">50dp</item>
        <item name="android:orientation">horizontal</item>
        <item name="android:background">@drawable/actionbar_background</item>
    </style>
 
    <style name="DashboardButton">
        <item name="android:layout_gravity">center_vertical</item>
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:gravity">center_horizontal</item>
        <item name="android:drawablePadding">2dp</item>
        <item name="android:textSize">16dp</item>
        <item name="android:textStyle">bold</item>
        <item name="android:textColor">#ff29549f</item>
        <item name="android:background">@null</item>
    </style>   
 
   <style name="FooterBar">
        <item name="android:layout_width">fill_parent</item>
        <item name="android:layout_height">40dp</item>
        <item name="android:orientation">horizontal</item>
        <item name="android:background">#dedede</item>
    </style>
</resources>
Source code
Android Styles (styles.xml) 
 https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/res/res/values/styles.xml
Android Themes (themes.xml)
 https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/res/res/values/themes.xml

Aquest fitxers permeten aprendre a través d'exemples. Per exemple aquí podeu trobar l'estil

<style name="Theme.Dialog">

User Interface Components

Normalment no és necessari construir totes les aplicacions a base de vistes i grups de vistes. Android proporciona el que s'anomenen app components que ofereixen un layout estandard (standard UI layout a partir del qual només cal definir el contingut:

Aquest components són:

http://developer.android.com/guide/topics/ui/overview.html

Navigation_Drawer

Vegeu Navigation_Drawer

Action Bar

Vegeu Action Bar

Dialogs

Status Notifications

Altres alternatives de disseny

Dashboard

Quick Actions

Esdeveniments. Input Events

Exemples

Pintar per pantalla

Vegeu l'exemple del tutorial Vogella;

Drawables

Icones

Templates per a icones:

http://developer.android.com/guide/practices/ui_guidelines/icon_design.html#templatespack

Android Asset Studio

http://android-ui-utils.googlecode.com/hg/asset-studio/dist/index.html

Gestures

Vegeu també Gestures

  • Touch: Triggers the default functionality for a given item. Action: Press, lift
  • Long press: Enters data selection mode. Allows you to select one or more items in a view and act upon the data using a contextual action bar. Avoid using long press for showing contextual menus. Action. Press, wait, lift
  • Swipe: Scrolls overflowing content, or navigates between views in the same hierarchy. Action. Press, move, lift
  • Drag: Rearranges data within a view, or moves data into a container (e.g. folders on Home Screen). Action. Long press, move, lift
  • Double touch: Zooms into content. Also used as a secondary gesture for text selection. Action. Two touches in quick succession
  • Pinch open: Zooms into content. Action 2-finger press, move outwards, lift
  • Pinch close: Zooms out of content. Action 2-finger press, move inwards, lift

Recursos:

Exemple de gesture. Pinch/escalar imatge

http://www.vogella.com/articles/AndroidTouch/article.html#touch

Patrons de disseny

DOS & DONT'S

Exemples

Pàgina de Login

http://www.androidhive.info/2011/10/android-login-and-registration-screen-design/

Disseny de la UI per a tablets

Fragments

Un fragment representa un comportament o una porció de la interfície d'usuari d'una Activitat Android. Es poden combinar múltiples fragments en una sola activitat per tal de crear una User Interface (aka UI) multi-pane i reutilitzar els fragments en múltiples activitats. Es pot pensar en un fragment com una secció modular d'una activitat.

Els fragments són com activitats anidades dins d'altres Activitats i que tenen el seu propi layout i cicle de vida.

Són com subactivitats que es poden reutilitzar en altres activitats

Un fragment sempre ha de estar dins d'una activitat i el cicle de vida del Fragment està associat al cicle de vida de l'activitat, per exemple si es destrueix una activitat també es destrueixen tots els fragments que conté. Cal tenir en compte però que quan una activitat esta executant-se, cada fragment es pot manipular de forma independent, com per exemple es pot afegir o eliminar. A aquestes accions les anomenen fragment transactions, per exemple es poden afegir a una back stack.

Quan s'afegeix un fragment al layout d'una activitat, s'ha de fer dins d'un ViewGroup i el fragment defineix el seu propi layout. S'utilitza l'element XML:

<fragment>

NOTA: Es poden utilitzar fragment que no formin part del layout de l'activitat, s'utilitzen com a invisible workers de l'activitat Android

Les qüestions que cal tenir en compte són:

  • Com mantenir l'estat dels fragments al afegir-los al back stack de l'activitat.
  • Com compartir esdeveniments amb l'activitat pare i altres fragments.
  • Com contribuir a l'Action bar de l'activitat pare.

En resum, el que cal tenir en compte dels Fragments és:

  • Descomposen la funcionalitat i el UI de les aplicacions en mòduls
  • S'afegeixen a una pantalla per evitar la commutació entre activitats.
  • Tenen el seu propi cicle de vida i back stack
  • Requereixen l'API 11 o superior o és pot utilitza la Llibreria de compatibilitat per suportar Fragments en dispositius anteriors a API 11.

Vegeu també Fragments

Recursos:

Convertir una activitat a Fragment

Cicle de vida

Versió completa del cicle de vida:

complete_android_fragment_lifecycle.png

Estats:

  • android-basiclifecycle.png


Vegeu també Cicle de vida de les Activitats Android i l'apartat Controlant el cicle de vida dels fragments

Filosofia de disseny

Els fragments es van introduir a la versió 3.0 (API level 11), sobretot per donar un millor suport i aplicacions més dinàmiques en pantalles grans, com les de les tablets.

Because a tablet's screen is much larger than that of a handset, there's more room to combine and interchange UI components. Fragments allow such designs without the need for you to manage complex changes to the view hierarchy. By dividing the layout of an activity into fragments, you become able to modify the activity's appearance at runtime and preserve those changes in a back stack that's managed by the activity.

For example, a news application can use one fragment to show a list of articles on the left and another fragment to display an article on the right—both fragments appear in one activity, side by side, and each fragment has its own set of lifecycle callback methods and handle their own user input events. Thus, instead of using one activity to select an article and another activity to read the article, the user can select an article and read it all within the same activity, as illustrated in the tablet layout in figure 1.

You should design each fragment as a modular and reusable activity component. That is, because each fragment defines its own layout and its own behavior with its own lifecycle callbacks, you can include one fragment in multiple activities, so you should design for reuse and avoid directly manipulating one fragment from another fragment. This is especially important because a modular fragment allows you to change your fragment combinations for different screen sizes. When designing your application to support both tablets and handsets, you can reuse your fragments in different layout configurations to optimize the user experience based on the available screen space. For example, on a handset, it might be necessary to separate fragments to provide a single-pane UI when more than one cannot fit within the same activity.

TODO: fragments.png
Figure 1. An example of how two UI modules defined by fragments can be combined into one activity for a tablet design, but separated for a handset design.

For example—to continue with the news application example—the application can embed two fragments in Activity A, when running on a tablet-sized device. However, on a handset-sized screen, there's not enough room for both fragments, so Activity A includes only the fragment for the list of articles, and when the user selects an article, it starts Activity B, which includes the second fragment to read the article. Thus, the application supports both tablets and handsets by reusing fragments in different combinations, as illustrated in figure 1.

For more information about designing your application with different fragment combinations for different screen configurations, see the guide to Supporting Tablets and Handsets.

La llibreria de compatibilitat i els Fragments

És possible utilitzar els Fragments en aplicacions inferiors a la 3.0 d'Android carregant a l'aplicació la llibreria:

Android Support Library

Cal tenir en compte que la classe nativa per a Fragments és:

android.app.Fragment

també però es pot carregar la llibreria:

android.support.v4.app.Fragment

Per a treballar amb Fragments que siguin de l'anterior clase (aplicacions amb compatibilitat cap endarrera) utilitzeu una Activitat del tipus:

No utilitzeu:

android.app.Activity

Sinó l'activitat de la llibreria:

android.support.v4.app.FragmentActivity

NOTA: Els projectes d'Android Studio solen incloure la llibreria de compatibilitat v7 que inclou v4 i per tant ja teniu el suport per a fragments instal·lat de sèrie

És a dir o tot natiu o tot de la llibreria de suport. Cal tenir en compte que no dona cap error de compilació sinó una excepció durant la execució.

A més cal tenir en compte:

  • Al crear una activitat que vulgueu que suporti fragments cal declarar-la com a filla (extends) de FragmentActivity.class (en comptes d'utilitzar l'activitat tradicional).
  • Per gestionar els fragments i els carregadors, cal utilitzar els mètodes:
FragmentActivity.getSupportFragmentManager()

i

FragmentActivity.getSupportLoaderManager()

en comptes de:

getFragmentManager()

i

getLoaderManager()

Com crear un fragment

IMPORTANT: Els Fragment no poden subsistir de forma independent i han de dependre de com a mínim una Activitat "pare". Vegeu el següent apartat. Això sí, un fragment es pot reutilitzar en múltiples activitats

Cicle de vida:

fragment_lifecycle.png

Per crear un fragment cal crear una classe filla de la classe Fragment:

http://developer.android.com/reference/android/app/Fragment.html

O encara és més habitual crear un Fragment amb la llibreria de compatibilitat (Android support):

import android.support.v4.app.Fragment;
...
public class SplashFragment extends Fragment {

Aquesta classe se sembla a la classe Activity i té callback methods molt similars com

onCreate(), onStart(), onPause() i onStop(). 

IMPORTANT: De fet per convertir codi amb només Activitats a codi amb fragments, simplement caldrà moure els mètodes esmentats

també però hi ha mètodes especifics associats al cicle de vida especific del Fragment.

Els mètodes a implementar són:

  • onCreate(): el sistema crida aquest mètodequan ha de crear el Fragment. A la vostra implementació, aquí s'inicialitzen components del fragment que s'utilitzaran en els atres mètodes del Fragment (onPaused, onStopped, onResume()...
  • onCreateView(): aquest mètode preparar la UI del fragment. És aqui (a diferència de les Activitats que ho fan a onCreate) on és fan les crides al layous i a la prepració de la UI del Fragment. Cal fer-ho així per tal que al onCreate de la activitat "pare" del fragment tot el tema de UI del Fragment estigui preparat per a la activitat. El mpetode retorna una View que és l'element arrel de la UI del fragment.
  • onPause(): es crida quan l'usuari deixa d'utilitzar el Fragment (que no vol dir que el Fragment es destrueixi). NOTA: This is usually where you should commit any changes that should be persisted beyond the current user session (because the user might not come back).

Aquest són els tres mètodes més habituals d'un Fragment però es poden implementar d'altres (vegeu la gràfica del cicle de vida).

Cal tenir en compte que l'API ja ens proporciona Fragments tipus com

Activitat contenedora de Fragments. FragmentActivity

Els fragments SEMPRE estan associats a una activitat. Les Activitats de Android de la API 11 (3.0) o superior suporten de "sèrie" fragments, però les activitats de APIs Android anteriors no. Per aquesta raó molt sovint veureu que les activitats que contenen fragments són filles de la clase FragmentActivity:

import android.support.v4.app.FragmentActivity;
...
public class MainActivity extends FragmentActivity {
...
}

Plantilla:IMPORTANT

TODO: A més les FragmentActivity estan més preprades per treballar amb Action Bars???

Recursos:

Afegir una interfície d'usuari a un fragment

La principal diferència respecte a com s'afegeixen els layous a una activitat, és que no ho farem al mètode onCreate sinó al mètode:

onCreateView()

que és el mètode que el sistema operatiu Android crida quan és el moment de que el fragment sigui dibuixat per pantalla. El mètode ha de tornar una vista (View) que sigui l'arrel del layout del fragment.

NOTA: si parlem de ListFragment, aleshores es retorna ListView

Es pot obtenir l'arrel del layout inflant-la a partir d'un layout resource definit en XML. Vegem un exemple de com utilitzar el fitxer example_fragment.xml com a layout d'un fragment.

public static class ExampleFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.example_fragment, container, false);
    }
}
Crear un layout

Vegem com ha de ser el fitxer de layout. De l'exemple anterior el fitxer example_fragment.xml. El paràmetre container és l'objecte:

ViewGroup

del layout de l'activitat pare, en el qual el fragment s'ha inserit.

El paràmetre savedInstanceState és un Bundle que permet fer persistent les dades de anteriors instàncies del fragment.

En tot cas els layouts es defineixen de forma similar a com es fa amb les activitats.

El mètode inflate() té 3 arguments:

  • El resource ID del layout del fragment
  • El ViewGroup del layout de l'activitat pare.
  • A boolean indicating whether the inflated layout should be attached to the ViewGroup (the second parameter) during inflation. (In this case, this is false because the system is already inserting the inflated layout into the container—passing true would create a redundant view group in the final layout.)

Afegint un fragment a una activitat

Hi ha dos formes de fer-ho:

  • Estàtica: Declarar el fragment dins del layout de l'activitat.
  • Dinàmica: per codi afegir el Fragment a un ViewGroup existent.

Estàtica

Vegem un exemple:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <fragment android:name="com.example.news.ArticleListFragment"
                android:id="@+id/list"
                android:layout_weight="1"
                android:layout_width="0dp"
                android:layout_height="match_parent" />
        <fragment android:name="com.example.news.ArticleReaderFragment"
                android:id="@+id/viewer"
                android:layout_weight="2"
                android:layout_width="0dp"
                android:layout_height="match_parent" />
    </LinearLayout>

On

android:name

indica la classe Fragment.

NOTA: Each fragment requires a unique identifier that the system can use to restore the fragment if the activity is restarted (and which you can use to capture the fragment to perform transactions, such as remove it). There are three ways to provide an ID for a fragment: Supply the android:id attribute with a unique ID. Supply the android:tag attribute with a unique string. If you provide neither of the previous two, the system uses the ID of the container view.

Dinàmica

S'utilitza l'API FragmentTransaction:

 FragmentManager fragmentManager = getFragmentManager()
 FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

Per afegir un fragment.

    ExampleFragment fragment = new ExampleFragment();
    fragmentTransaction.add(R.id.fragment_container, fragment);
    fragmentTransaction.commit();

Afegint fragments a una activitat (amagats per defecte)

Una tècnica utilitzada en aplicacions com Scrumptious és crear tots els fragments AMAGATS al mètode onCreate de la classe que hereteu de FragmentActivity:

FragmentManager fm = getSupportFragmentManager();
       SplashFragment splashFragment = (SplashFragment) fm.findFragmentById(R.id.splashFragment);
       fragments[SPLASH] = splashFragment;
       fragments[SELECTION] = fm.findFragmentById(R.id.selectionFragment);
       fragments[SETTINGS] = fm.findFragmentById(R.id.userSettingsFragment);

       FragmentTransaction transaction = fm.beginTransaction();
       for(int i = 0; i < fragments.length; i++) {
           transaction.hide(fragments[i]);
       }
       transaction.commit();

I mostrar només un fragment en el moment que es necessiti amb la funció (amb support per addToBackStack). A l'exemple es mostra una pantalla de Login si l'usuari no està logat i sinó es consulten propietats de l'Activitat per saber que mostrar:

private void showFragment(int fragmentIndex, boolean addToBackStack) {
       FragmentManager fm = getSupportFragmentManager();
       FragmentTransaction transaction = fm.beginTransaction();
       for (int i = 0; i < fragments.length; i++) {
           if (i == fragmentIndex) {
               transaction.show(fragments[i]);
           } else {
               transaction.hide(fragments[i]);
           }
       }
       if (addToBackStack) {
           transaction.addToBackStack(null);
       }
       transaction.commit();
   }

Normalment al mètode onResumeFragments hi ha la lògica del controlador de quin fragment mostrar en cada moment:

protected void onResumeFragments() {
       super.onResumeFragments();
       Session session = Session.getActiveSession();

       if (session != null && session.isOpened()) {
           // if the session is already open, try to show the selection fragment
           showFragment(SELECTION, false);
           userSkippedLogin = false;
       } else if (userSkippedLogin) {
           showFragment(SELECTION, false);
       } else {
           // otherwise present the splash screen and ask the user to login, unless the user explicitly skipped.
           showFragment(SPLASH, false);
       }
   }

Com realitzar transaccions entre fragments

Una diferència important respecte a les activitats eś que podem utilitzar FragmentManager:

http://developer.android.com/reference/android/app/FragmentManager.html

Per afegir, eliminar o reemplaçar dinàmicament fragments a més d'altres accions en resposta a la interacció amb l'usuari.

Cada conjunt de canvis que es fan a una activitat els anomenem:

transaccions

i es poden realitzar utilitzant l'API FragmentTransaction:

http://developer.android.com/reference/android/app/FragmentTransaction.html

Això permet entre d'altres navegar endarrere entre fragments de la mateixa forma que ho fem amb les activitats.

Per obtenir un gestor de fragments:

 FragmentManager fragmentManager = getFragmentManager();
 FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

Cada transacció és un conjunt de canvis que es volen aplicar al mateix temps (de forma similar al concepte de transacció en base de dades). S'indiquen els canvis que es volen fer i un cop es volen aplicar de cop es crida a:

commit()

Sovint però abans de cridar commit es voldrà cridar:

 addToBackStack()

Per permetre la navegació endarrere. un exemple:

 // Create new fragment and transaction
 Fragment newFragment = new ExampleFragment();
 FragmentTransaction transaction = getFragmentManager().beginTransaction();

 // Replace whatever is in the fragment_container view with this fragment,
 // and add the transaction to the back stack
 transaction.replace(R.id.fragment_container, newFragment);
 transaction.addToBackStack(null);

 // Commit the transaction
 transaction.commit();

A l'exemple el fragment newFragment reemplaça el fragment actual.

NOTA: For each fragment transaction, you can apply a transition animation, by calling setTransition() before you commit

Calling commit() does not perform the transaction immediately. Rather, it schedules it to run on the activity's UI thread (the "main" thread) as soon as the thread is able to do so. If necessary, however, you may call executePendingTransactions() from your UI thread to immediately execute transactions submitted by commit(). Doing so is usually not necessary unless the transaction is a dependency for jobs in other threads.

Caution: You can commit a transaction using commit() only prior to the activity saving its state (when the user leaves the activity). If you attempt to commit after that point, an exception will be thrown. This is because the state after the commit can be lost if the activity needs to be restored. For situations in which its okay that you lose the commit, use commitAllowingStateLoss().

Afegint ítems al Action Bar

Els fragments poden crear ítems de menú al menú d'opcions ( i conseqüentment a l'Action Bar si s'escau) implementant el mètode:

onCreateOptionsMenu()

De fet igual que fan les activitats. Cal tenir en compte però que per rebre crides cal establir:

setHasOptionsMenu() 

Al:

onCreate()

Del Action Bar

You can also register a view in your fragment layout to provide a context menu by calling registerForContextMenu(). When the user opens the context menu, the fragment receives a call to onCreateContextMenu(). When the user selects an item, the fragment receives a call to onContextItemSelected().

Note: Although your fragment receives an on-item-selected callback for each menu item it adds, the activity is first to receive the respective callback when the user selects a menu item. If the activity's implementation of the on-item-selected callback does not handle the selected item, then the event is passed to the fragment's callback. This is true for the Options Menu and context menus.

For more information about menus, see the Menus and Action Bar developer guides.

Exemples

Controlant el cicle de vida

Comproveu la gràfica del cicle de vida d'un fragment (i la comparació amb l'activitat paralela)

TODO
http://developer.android.com/guide/components/fragments.html#Lifecycle

i el cicle de vida resumit d'una activitat:

android-basiclifecycle.png

Com les Actvitats un Fragment pot tenir 4 estats i existir en 3 estats:

  • Resumed: The fragment is visible in the running activity.
  • Paused: Another activity is in the foreground and has focus, but the activity in which this fragment lives is still visible (the foreground activity is partially transparent or doesn't cover the entire screen).
  • Stopped: El fragment no és visible. Pot ser per que la activitat host (pare) s'ha aturat o per que el fragment ha estat tret de la activitat però afegit a la back stack. Un fragment aturat encara és viu ( es guarda la informació d'estat) però pot ser eliminat si l'activita host és eliminada.
  • Eliminat

La diferència més important entre el cicle de vida d'una Activitat i un Fragment es com es guarda a la back stack. Les activitats són gestionades per defecte pel sistema per defecte. En canvi un fragment només es guarda a la backstak gestionada per la host Activity si li indiquem explicitament cridant a la funció addToBackStack() durant una transacció que elimina el fragment.

Also like an activity, you can retain the state of a fragment using a Bundle, in case the activity's process is killed and you need to restore the fragment state when the activity is recreated. You can save the state during the fragment's onSaveInstanceState() callback and restore it during either onCreate(), onCreateView(), or onActivityCreated(). For more information about saving state, see the Activities document.

IMPORTANT: Caution: If you need a Context object within your Fragment, you can call getActivity(). However, be careful to call getActivity() only when the fragment is attached to an activity. When the fragment is not yet attached, or was detached during the end of its lifecycle, getActivity() will return null.

El cicle de vida del fragment està associat amb el de l'activitat host. Per exemple si es crida al mètode onPause() de l'activitat, CADA fragment de la activitat també executarà onPause(). Els fragments però tenen callbacks extres:

  • onAttach(): Called when the fragment has been associated with the activity (the Activity is passed in here).
  • onCreateView(): Called to create the view hierarchy associated with the fragment.
  • onActivityCreated(): Called when the activity's onCreate() method has returned.
  • onDestroyView(): Called when the view hierarchy associated with the fragment is being removed.
  • onDetach(): Called when the fragment is being disassociated from the activity.

Vegeu la gràfica completa a:

http://developer.android.com/guide/components/fragments.html#Lifecycle


Coordinant-se amb el cicle de vida de la Activitat host

Once the activity reaches the resumed state, you can freely add and remove fragments to the activity. Thus, only while the activity is in the resumed state can the lifecycle of a fragment change independently.

However, when the activity leaves the resumed state, the fragment again is pushed through its lifecycle by the activity.

Example

To bring everything discussed in this document together, here's an example of an activity using two fragments to create a two-pane layout. The activity below includes one fragment to show a list of Shakespeare play titles and another to show a summary of the play when selected from the list. It also demonstrates how to provide different configurations of the fragments, based on the screen configuration.

Note: The complete source code for this activity is available in FragmentLayout.java.

The main activity applies a layout in the usual way, during onCreate():

@Override protected void onCreate(Bundle savedInstanceState) {

   super.onCreate(savedInstanceState);
   setContentView(R.layout.fragment_layout);

}

The layout applied is fragment_layout.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

   android:orientation="horizontal"
   android:layout_width="match_parent" android:layout_height="match_parent">
   <fragment class="com.example.android.apis.app.FragmentLayout$TitlesFragment"
           android:id="@+id/titles" android:layout_weight="1"
           android:layout_width="0px" android:layout_height="match_parent" />
   <FrameLayout android:id="@+id/details" android:layout_weight="1"
           android:layout_width="0px" android:layout_height="match_parent"
           android:background="?android:attr/detailsElementBackground" />

</LinearLayout>

Using this layout, the system instantiates the TitlesFragment (which lists the play titles) as soon as the activity loads the layout, while the FrameLayout (where the fragment for showing the play summary will go) consumes space on the right side of the screen, but remains empty at first. As you'll see below, it's not until the user selects an item from the list that a fragment is placed into the FrameLayout.

However, not all screen configurations are wide enough to show both the list of plays and the summary, side by side. So, the layout above is used only for the landscape screen configuration, by saving it at res/layout-land/fragment_layout.xml.

Thus, when the screen is in portrait orientation, the system applies the following layout, which is saved at res/layout/fragment_layout.xml:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"

   android:layout_width="match_parent" android:layout_height="match_parent">
   <fragment class="com.example.android.apis.app.FragmentLayout$TitlesFragment"
           android:id="@+id/titles"
           android:layout_width="match_parent" android:layout_height="match_parent" />

</FrameLayout>

This layout includes only TitlesFragment. This means that, when the device is in portrait orientation, only the list of play titles is visible. So, when the user clicks a list item in this configuration, the application will start a new activity to show the summary, instead of loading a second fragment.

Next, you can see how this is accomplished in the fragment classes. First is TitlesFragment, which shows the list of Shakespeare play titles. This fragment extends ListFragment and relies on it to handle most of the list view work.

As you inspect this code, notice that there are two possible behaviors when the user clicks a list item: depending on which of the two layouts is active, it can either create and display a new fragment to show the details in the same activity (adding the fragment to the FrameLayout), or start a new activity (where the fragment can be shown).

public static class TitlesFragment extends ListFragment {

   boolean mDualPane;
   int mCurCheckPosition = 0;
   @Override
   public void onActivityCreated(Bundle savedInstanceState) {
       super.onActivityCreated(savedInstanceState);
       // Populate list with our static array of titles.
       setListAdapter(new ArrayAdapter<String>(getActivity(),
               android.R.layout.simple_list_item_activated_1, Shakespeare.TITLES));
       // Check to see if we have a frame in which to embed the details
       // fragment directly in the containing UI.
       View detailsFrame = getActivity().findViewById(R.id.details);
       mDualPane = detailsFrame != null && detailsFrame.getVisibility() == View.VISIBLE;
       if (savedInstanceState != null) {
           // Restore last state for checked position.
           mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);
       }
       if (mDualPane) {
           // In dual-pane mode, the list view highlights the selected item.
           getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
           // Make sure our UI is in the correct state.
           showDetails(mCurCheckPosition);
       }
   }
   @Override
   public void onSaveInstanceState(Bundle outState) {
       super.onSaveInstanceState(outState);
       outState.putInt("curChoice", mCurCheckPosition);
   }
   @Override
   public void onListItemClick(ListView l, View v, int position, long id) {
       showDetails(position);
   }
   /**
    * Helper function to show the details of a selected item, either by
    * displaying a fragment in-place in the current UI, or starting a
    * whole new activity in which it is displayed.
    */
   void showDetails(int index) {
       mCurCheckPosition = index;
       if (mDualPane) {
           // We can display everything in-place with fragments, so update
           // the list to highlight the selected item and show the data.
           getListView().setItemChecked(index, true);
           // Check what fragment is currently shown, replace if needed.
           DetailsFragment details = (DetailsFragment)
                   getFragmentManager().findFragmentById(R.id.details);
           if (details == null || details.getShownIndex() != index) {
               // Make new fragment to show this selection.
               details = DetailsFragment.newInstance(index);
               // Execute a transaction, replacing any existing fragment
               // with this one inside the frame.
               FragmentTransaction ft = getFragmentManager().beginTransaction();
               if (index == 0) {
                   ft.replace(R.id.details, details);
               } else {
                   ft.replace(R.id.a_item, details);
               }
               ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
               ft.commit();
           }
       } else {
           // Otherwise we need to launch a new activity to display
           // the dialog fragment with selected text.
           Intent intent = new Intent();
           intent.setClass(getActivity(), DetailsActivity.class);
           intent.putExtra("index", index);
           startActivity(intent);
       }
   }

}

The second fragment, DetailsFragment shows the play summary for the item selected from the list from TitlesFragment:

public static class DetailsFragment extends Fragment {

   /**
    * Create a new instance of DetailsFragment, initialized to
    * show the text at 'index'.
    */
   public static DetailsFragment newInstance(int index) {
       DetailsFragment f = new DetailsFragment();
       // Supply index input as an argument.
       Bundle args = new Bundle();
       args.putInt("index", index);
       f.setArguments(args);
       return f;
   }
   public int getShownIndex() {
       return getArguments().getInt("index", 0);
   }
   @Override
   public View onCreateView(LayoutInflater inflater, ViewGroup container,
           Bundle savedInstanceState) {
       if (container == null) {
           // We have different layouts, and in one of them this
           // fragment's containing frame doesn't exist.  The fragment
           // may still be created from its saved state, but there is
           // no reason to try to create its view hierarchy because it
           // won't be displayed.  Note this is not needed -- we could
           // just run the code below, where we would create and return
           // the view hierarchy; it would just never be used.
           return null;
       }
       ScrollView scroller = new ScrollView(getActivity());
       TextView text = new TextView(getActivity());
       int padding = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
               4, getActivity().getResources().getDisplayMetrics());
       text.setPadding(padding, padding, padding, padding);
       scroller.addView(text);
       text.setText(Shakespeare.DIALOGUE[getShownIndex()]);
       return scroller;
   }

}

Recall from the TitlesFragment class, that, if the user clicks a list item and the current layout does not include the R.id.details view (which is where the DetailsFragment belongs), then the application starts the DetailsActivity activity to display the content of the item.

Here is the DetailsActivity, which simply embeds the DetailsFragment to display the selected play summary when the screen is in portrait orientation:

public static class DetailsActivity extends Activity {

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       if (getResources().getConfiguration().orientation
               == Configuration.ORIENTATION_LANDSCAPE) {
           // If the screen is now in landscape mode, we can show the
           // dialog in-line with the list so we don't need this activity.
           finish();
           return;
       }
       if (savedInstanceState == null) {
           // During initial setup, plug in the details fragment.
           DetailsFragment details = new DetailsFragment();
           details.setArguments(getIntent().getExtras());
           getFragmentManager().beginTransaction().add(android.R.id.content, details).commit();
       }
   }

}

Notice that this activity finishes itself if the configuration is landscape, so that the main activity can take over and display the DetailsFragment alongside the TitlesFragment. This can happen if the user begins the DetailsActivity while in portrait orientation, but then rotates to landscape (which restarts the current activity).

For more samples using fragments (and complete source files for this example), see the API Demos sample app available in ApiDemos (available for download from the Samples SDK component).

Comunicant-se amb altres Fragments i l'activitat pare

La filosofia dels fragment es que siguin reutilitzables. Per tal de poder reutilitzar els components d'interfície gràfica dels Fragments, cal crear cada fragment de forma que siguin components modulars complets i auto-continguts i que defineixen el seu propi Layout i comportament.

Un cop definits, els fragments es poden associar a una activitat i connectar-los entre si amb la lògica de l'aplicació per tal de crear una interfície gràfica composta per múltiples fragments.

Sovint és important que un Fragment es comuniqui amb un altre, per exemple per a intercanviar contingut basant-se en un esdeveniment d'usuari

IMPORTANT: Totes les comunicacions entre fragments es realitzen a través de l'Activitat associada. Dos Fragment no s'han de comunicar mai directament

Sovint el que es fa per tal que el Fragment es pugui comunicar amb la seva activitat pare, es definir una interfície a la classe Fragment i s'implementa a l'activitat pare.

NOTA: Vegeu l'exemple que genera automàticament Eclipse d'una aplicació multipane amb un fragment amb la llista d'articles i un fragment amb els detalls

És important capturar l'activitat pare al mètode OnAttach. Vegem un exemple:

public class HeadlinesFragment extends ListFragment {
    
    OnHeadlineSelectedListener mCallback;

    // Container Activity must implement this interface
    public interface OnHeadlineSelectedListener {
        public void onArticleSelected(int position);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        
        // This makes sure that the container activity has implemented
        // the callback interface. If not, it throws an exception
        try {
            mCallback = (OnHeadlineSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement OnHeadlineSelectedListener");
        }
    }
    
    ...
}

Ara el fragment es pot comunicat amb l'activitat pare cridant al mètode:

onArticleSelected()

o altres mètodes de la interfície utilitzant l'atribut mCallback que conté l'activitat pare.

NOTA: Els noms dels mètodes són de lliure elecció

Cal tenir en compte que al programar l'activitat caldrà implementar la interfície i també omplir de codi el mètode per realitzar les accions que calguin.

Vegem un exemple de com comunicar-se amb l'activitat pare quan l'usuari selecciona un ítem de la llista:

    
    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        // Send the event to the host activity
        mCallback.onArticleSelected(position);
    }

Com s'ha d'implementar la interfície:

 
public static class MainActivity extends Activity
        implements HeadlinesFragment.OnHeadlineSelectedListener{
    ...
    
    public void onArticleSelected(int position) {
        // The user selected the headline of an article from the HeadlinesFragment
        // Do something here to display that article
    }
}

Enviar missatges de l'activitat als fragments

L'activitat pare (aka host activity) pot comunicar-se amb els fragments obtenint una instància del Fragment amb:

findFragmentById()

I aleshores cridar directament als seu mètodes públics. Podem veure com es fa en el típic exemple multi-pane llista d'items/detall:

 
public static class MainActivity extends Activity
        implements HeadlinesFragment.OnHeadlineSelectedListener{
    ...

    public void onArticleSelected(int position) {
        // The user selected the headline of an article from the HeadlinesFragment
        // Do something here to display that article

        ArticleFragment articleFrag = (ArticleFragment)
                getSupportFragmentManager().findFragmentById(R.id.article_fragment);

        if (articleFrag != null) {
            // If article frag is available, we're in two-pane layout...

            // Call a method in the ArticleFragment to update its content
            articleFrag.updateArticleView(position);
        } else {
            // Otherwise, we're in the one-pane layout and must swap frags...

            // Create fragment and give it an argument for the selected article
            ArticleFragment newFragment = new ArticleFragment();
            Bundle args = new Bundle();
            args.putInt(ArticleFragment.ARG_POSITION, position);
            newFragment.setArguments(args);
        
            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

            // Replace whatever is in the fragment_container view with this fragment,
            // and add the transaction to the back stack so the user can navigate back
            transaction.replace(R.id.fragment_container, newFragment);
            transaction.addToBackStack(null);

            // Commit the transaction
            transaction.commit();
        }
    }
}

Recursos:

getActivity().findViewById() i FragmentManager/getFragmentManager

Des dels fragments es pot accedir a l'activitat pare amb

 View listView = getActivity().findViewById(R.id.list);

L'activitat pot cridar a mètodes dels Fragments amb FragmentManager i utilitzar findFragmentById() o findFragmentByTag():

 ExampleFragment fragment = (ExampleFragment)  
 getFragmentManager().findFragmentById(R.id.example_fragment);
popBackStack()

El mètode:

popBackStack()

Simular una comanda back, com si l'usuari premès el botó back. Cal que s'haguin guardat les accions dels Fragments a la back stack.

Gestionant Fragments amb FragmentManager

Es poden gestionar els Fragments amb el mètode:

getFragmentManager()

que retorna un objecte de tipus FragmentManager. Aquest mètode existeix a totes les activitats.

Que es pot fer?

Afegint un fragment sense UI (background Fragments)

TODO

The examples above show how to add a fragment to your activity in order to provide a UI. However, you can also use a fragment to provide a background behavior for the activity without presenting additional UI.

To add a fragment without a UI, add the fragment from the activity using add(Fragment, String) (supplying a unique string "tag" for the fragment, rather than a view ID). This adds the fragment, but, because it's not associated with a view in the activity layout, it does not receive a call to onCreateView(). So you don't need to implement that method.

Supplying a string tag for the fragment isn't strictly for non-UI fragments—you can also supply string tags to fragments that do have a UI—but if the fragment does not have a UI, then the string tag is the only way to identify it. If you want to get the fragment from the activity later, you need to use findFragmentByTag().

For an example activity that uses a fragment as a background worker, without a UI, see the FragmentRetainInstance.java sample.

Com guardar l'estat d'un fragment

Cal tenir en compte que els fragments poden tenir que ser recreats segons el cicla de vida de l'aplicació. Per exemple una rotació de la pantalla pot provocar que el sistema guardi l'estat del fragmenti el recuperir al tornar a pintar el fragment.

Per guardar l'estat cal implementar/sobrescriure onSaveInstanceState on es pot modificar el Bundle. Un exemple:

  @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

        // Save the current article selection in case we need to recreate the fragment
        outState.putInt(ARG_POSITION, mCurrentPosition);
    }

Un exemple extret de l'exemple de:

 http://developer.android.com/training/basics/fragments/index.html


public class ArticleFragment extends Fragment {

    final static String ARG_POSITION = "position";
    int mCurrentPosition = -1;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
        Bundle savedInstanceState) {

        // If activity recreated (such as from screen rotate), restore
        // the previous article selection set by onSaveInstanceState().
        // This is primarily necessary when in the two-pane layout.
        if (savedInstanceState != null) {
            mCurrentPosition = savedInstanceState.getInt(ARG_POSITION);
        }

        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.article_view, container, false);
    }

    ...

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

        // Save the current article selection in case we need to recreate the fragment
        outState.putInt(ARG_POSITION, mCurrentPosition);
    }
}

Exemple amb ListFragment

El trobareu a Eclipse al crear un nou projecte, utilitzant l'exemple llista/detall.

Vegeu també Android_UI_Development#ArrayAdapter_amb_ListFragment

Exemples

Pestanyes i fragments (ActionBar tabs)

Cal crear un fragment per cada pestanya. Sovint els fragments es creen com classe anidades o com fitxers per cada classe.

Vegeu l'exemple:

http://android-des.blogspot.com.es/2013/04/action-bar-scrollable-tabs.html

La clau està en el mètode:

public Fragment getItem(int position) {}

de la classe SectionsPagerAdapter que és filla de FragmentPagerAdapter [7]:

  • Position és el número de pestanya actiu en aquell moment contant de esquerra a dreta
  • El mètode ha de retornar el fragment ja preparat, és a dir, amb layout definit i altres configuracions prèvies a ser mostrat

Recursos:

Recursos alternatius

Vegeu també Recursos alternatius

Components a mida

TODO

Android Cards

Vegeu Android Cards

Troubleshooting. Resol·lució de problemes

Els fragments en tabs se solapen al canviar la orientació de la pantalla

Cal comprovar el paràmetre savedInstanceState, per tal que si es ve d'una recuperació d'una instància ja existent no es torni a crear el fragment:

           // However, if we're being restored from a previous state,
           // then we don't need to do anything and should return or else
           // we could end up with overlapping fragments.
           if (savedInstanceState != null) {
               return;
           }
Also if you have problem with fragments overlapping after orientation change its properly related to 
savedinstancestate passed on. Here is a copy paste from a google tutorial that explains the fragment overlapping 
issue and how to avoid it:

Recursos:

Vegeu també

Enllaços externs