Home | History | Annotate | Download | only in multiscreen
      1 page.title=Cmo implementar interfaces de usuario adaptables
      2 parent.title=Cmo disear aplicaciones para varias pantallas
      3 parent.link=index.html
      4 
      5 trainingnavtop=true
      6 previous.title=Cmo admitir varias densidades de pantalla
      7 previous.link=screendensities.html
      8 
      9 @jd:body
     10 
     11 
     12 <!-- This is the training bar -->
     13 <div id="tb-wrapper"> 
     14 <div id="tb"> 
     15  
     16 <h2>En esta seccin puedes aprender:</h2>
     17 
     18 <ol>
     19   <li><a href="#TaskDetermineCurLayout">Cmo determinar el diseo actual</a></li>
     20   <li><a href="#TaskReactToLayout">Cmo reaccionar en funcin del diseo actual</a></li>
     21   <li><a href="#TaskReuseFrag">Cmo volver a utilizar fragmentos en otras actividades</a></li>
     22   <li><a href="#TaskHandleConfigChanges">Cmo gestionar los cambios en la configuracin de la pantalla</a></li>
     23 </ol>
     24 
     25 <h2>Tambin puedes consultar:</h2>
     26 
     27 <ul>
     28   <li><a href="{@docRoot}guide/practices/tablets-and-handsets.html">Cmo admitir tablets y dispositivos mviles</a></li>
     29 </ul>
     30  
     31 <h2>Prubalo!</h2>
     32  
     33 <div class="download-box">
     34 <a href="http://developer.android.com/shareables/training/NewsReader.zip" class="button">Descargar la aplicacin de ejemplo</a>
     35 <p class="filename">NewsReader.zip</p> 
     36 </div> 
     37  
     38  
     39 </div> 
     40 </div> 
     41 
     42 <p>En funcin del diseo actual de tu aplicacin, la interfaz puede variar. Por ejemplo, si tu aplicacin est en modo de panel dual, haz clic en un elemento del panel izquierdo para que aparezca en el panel de la derecha. Asimismo, si est en modo de panel nico, el contenido debera aparecer por s mismo (en otra actividad).</p>
     43 
     44 
     45 <h2 id="TaskDetermineCurLayout">Cmo determinar el diseo actual</h2>
     46 
     47 <p>Dado que la implementacin de cada diseo variar en cierta medida, probablemente una de las primeras cosas que tendrs que hacer ser determinar el diseo que el usuario puede ver en ese momento. Por ejemplo, puedes determinar si el usuario utiliza el modo de "panel nico" o de "panel dual". Para ello, puedes consultar si una vista determinada existe y es visible:</p>
     48 
     49 <pre class="prettyprint">
     50 public class NewsReaderActivity extends FragmentActivity {
     51     boolean mIsDualPane;
     52 
     53     &#64;Override
     54     public void onCreate(Bundle savedInstanceState) {
     55         super.onCreate(savedInstanceState);
     56         setContentView(R.layout.main_layout);
     57 
     58         View articleView = findViewById(R.id.article);
     59         mIsDualPane = articleView != null &amp;&amp; 
     60                         articleView.getVisibility() == View.VISIBLE;
     61     }
     62 }
     63 </pre>
     64 
     65 <p>Ten en cuenta que este cdigo consulta la disponibilidad del panel del "artculo", lo que es mucho ms flexible que incluir una consulta para un diseo determinado.</p>
     66 
     67 <p>Otro ejemplo de cmo puedes adaptar la existencia de diferentes componentes es comprobar su disponibilidad antes de realizar una operacin relacionada con los mismos. Por ejemplo, en la aplicacin de ejemplo News Reader, hay un botn que abre un men, pero ese botn solo aparece en las versiones anteriores a Android 3.0 (porque  <PH>{@link android.app.ActionBar}</PH> en el nivel 11 del API y en niveles superiores). Por tanto, para aadir el detector de eventos para este botn, puedes hacer lo siguiente:</p>
     68 
     69 <pre class="prettyprint">
     70 Button catButton = (Button) findViewById(R.id.categorybutton);
     71 OnClickListener listener = /* create your listener here */;
     72 if (catButton != null) {
     73     catButton.setOnClickListener(listener);
     74 }
     75 </pre>
     76 
     77 
     78 <h2 id="TaskReactToLayout">Cmo reaccionar en funcin del diseo actual</h2>
     79 
     80 <p>El resultado de algunas acciones puede variar en funcin del diseo actual. Por ejemplo, en el ejemplo de News Reader, al hacer clic en un encabezado de la lista se abrir el artculo del panel situado a la derecha si la interfaz de usuario est en modo de panel dual, pero se iniciar una actividad independiente si esta est en modo de panel nico:</p>
     81 
     82 <pre>
     83 &#64;Override
     84 public void onHeadlineSelected(int index) {
     85     mArtIndex = index;
     86     if (mIsDualPane) {
     87         /* display article on the right pane */
     88         mArticleFragment.displayArticle(mCurrentCat.getArticle(index));
     89     } else {
     90         /* start a separate activity */
     91         Intent intent = new Intent(this, ArticleActivity.class);
     92         intent.putExtra("catIndex", mCatIndex);
     93         intent.putExtra("artIndex", index);
     94         startActivity(intent);
     95     }
     96 }
     97 </pre>
     98 
     99 <p>De igual modo, si la aplicacin est en modo de panel dual, debe configurar la barra de accin con pestaas para la navegacin, mientras que si la aplicacin est en modo de panel nico, debe configurar la navegacin con un widget giratorio. Por tanto, el cdigo debe comprobar tambin cul es el caso adecuado:</p>
    100 
    101 <pre>
    102 final String CATEGORIES[] = { "Top Stories", "Politics", "Economy", "Technology" };
    103 
    104 public void onCreate(Bundle savedInstanceState) {
    105     ....
    106     if (mIsDualPane) {
    107         /* use tabs for navigation */
    108         actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_TABS);
    109         int i;
    110         for (i = 0; i &lt; CATEGORIES.length; i++) {
    111             actionBar.addTab(actionBar.newTab().setText(
    112                 CATEGORIES[i]).setTabListener(handler));
    113         }
    114         actionBar.setSelectedNavigationItem(selTab);
    115     }
    116     else {
    117         /* use list navigation (spinner) */
    118         actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_LIST);
    119         SpinnerAdapter adap = new ArrayAdapter<String>(this, 
    120                 R.layout.headline_item, CATEGORIES);
    121         actionBar.setListNavigationCallbacks(adap, handler);
    122     }
    123 }
    124 </pre>
    125 
    126 
    127 <h2 id="TaskReuseFrag">Cmo volver a utilizar fragmentos en otras actividades</h2>
    128 
    129 <p>Un patrn recurrente a la hora de disear para distintas pantallas es utilizar una parte de la interfaz que se implementa como un panel en algunas configuraciones de pantalla y como actividad independiente en otras. Por ejemplo, en el ejemplo de News Reader, el texto del artculo de noticias se presenta en el panel de la derecha en las pantallas grandes, pero es una actividad independiente en las pantallas ms pequeas.</p>
    130 
    131 <p>En otros casos similares, puedes evitar la duplicacin de cdigo reutilizando la misma <PH>{@link android.app.Fragment}</PH> en distintas actividades. Por ejemplo, <code>ArticleFragment</code> se utiliza en el diseo de panel dual:</p>
    132 
    133 {@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all}
    134 
    135 <p>A continuacin, se vuelve a utilizar (sin diseo) en el diseo de actividad para pantallas ms pequeas (<code>ArticleActivity</code>):</p>
    136 
    137 <pre>
    138 ArticleFragment frag = new ArticleFragment();
    139 getSupportFragmentManager().beginTransaction().add(android.R.id.content, frag).commit();
    140 </pre>
    141 
    142 <p>Evidentemente, esto tiene el mismo efecto que declarar el fragmento en un diseo XML. Sin embargo, en este caso, un diseo XML sera un trabajo innecesario porque el fragmento del artculo es el nico componente de esta actividad.</p>
    143 
    144 <p>Un punto muy importante que debes tener en cuenta al disear tus fragmentos es no crear un acoplamiento fuerte para una actividad determinada. Para ello, normalmente puedes definir una interfaz que resuma todas las formas en las que tiene que interactuar el fragmento con su actividad principal y, a continuacin, la actividad principal implementa esa interfaz:</p>
    145 
    146 <p>Por ejemplo, ese es precisamente el objetivo del <code>HeadlinesFragment</code> de la aplicacin News Reader:</p>
    147 
    148 <pre>
    149 public class HeadlinesFragment extends ListFragment {
    150     ...
    151     OnHeadlineSelectedListener mHeadlineSelectedListener = null;
    152 
    153     /* Must be implemented by host activity */
    154     public interface OnHeadlineSelectedListener {
    155         public void onHeadlineSelected(int index);
    156     }
    157     ...
    158 
    159     public void setOnHeadlineSelectedListener(OnHeadlineSelectedListener listener) {
    160         mHeadlineSelectedListener = listener;
    161     }
    162 }
    163 </pre>
    164 
    165 <p>A continuacin, cuando el usuario selecciona un encabezado, el fragmento notifica el detector especificado por la actividad principal (en lugar de notificar una actividad predefinida especfica):</p>
    166 
    167 <pre>
    168 public class HeadlinesFragment extends ListFragment {
    169     ...
    170     &#64;Override
    171     public void onItemClick(AdapterView&lt;?&gt; parent, 
    172                             View view, int position, long id) {
    173         if (null != mHeadlineSelectedListener) {
    174             mHeadlineSelectedListener.onHeadlineSelected(position);
    175         }
    176     }
    177     ...
    178 }
    179 </pre>
    180 
    181 <p>Si quieres obtener ms informacin sobre esta tcnica, puedes consultar la gua sobre <a
    182 href="{@docRoot}guide/practices/tablets-and-handsets.html">Cmo admitir tablets y dispositivos mviles</a>.</p>
    183 
    184 
    185 <h2 id="TaskHandleConfigChanges">Cmo gestionar los cambios en la configuracin de la pantalla</h2>
    186 
    187 <p>Si utilizas actividades independientes para implementar partes individuales de tu interfaz, debes tener en cuenta que es posible que tengas que reaccionar ante determinados cambios en la configuracin (como un cambio de rotacin) para mantener la homogeneidad de tu interfaz.</p>
    188 
    189 <p>Por ejemplo, en un tablet de 7" que utilice Android 3.0 o una versin superior, el ejemplo de News Reader utiliza una actividad independiente para mostrar el artculo de noticias en el modo vertical, pero utiliza el diseo de panel dual en el modo horizontal.</p>
    190 
    191 <p>Esto significa que cuando el usuario utiliza el modo vertical y est consultando un artculo, tienes que detectar que la orientacin ha cambiado al modo horizontal y reaccionar de forma adecuada finalizando la actividad. A continuacin, debes volver a la actividad principal para que el contenido pueda mostrarse en el diseo de panel dual:</p>
    192 
    193 <pre>
    194 public class ArticleActivity extends FragmentActivity {
    195     int mCatIndex, mArtIndex;
    196 
    197     &#64;Override
    198     protected void onCreate(Bundle savedInstanceState) {
    199         super.onCreate(savedInstanceState);
    200         mCatIndex = getIntent().getExtras().getInt("catIndex", 0);
    201         mArtIndex = getIntent().getExtras().getInt("artIndex", 0);
    202 
    203         // If should be in two-pane mode, finish to return to main activity
    204         if (getResources().getBoolean(R.bool.has_two_panes)) {
    205             finish();
    206             return;
    207         }
    208         ...
    209 }
    210 </pre>
    211 
    212 
    213