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 @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 && 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 @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 < 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 @Override 171 public void onItemClick(AdapterView<?> 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 @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