diff options
Diffstat (limited to 'docs/html-intl/ru')
9 files changed, 1018 insertions, 0 deletions
diff --git a/docs/html-intl/ru/training/monitoring-device-state/battery-monitoring.jd b/docs/html-intl/ru/training/monitoring-device-state/battery-monitoring.jd new file mode 100644 index 0000000..26daf04 --- /dev/null +++ b/docs/html-intl/ru/training/monitoring-device-state/battery-monitoring.jd @@ -0,0 +1,120 @@ +page.title=Monitoring the Battery Level and Charging State +parent.title=Optimizing Battery Life +parent.link=index.html + +trainingnavtop=true +next.title=Determining and Monitoring the Docking State and Type +next.link=docking-monitoring.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>Содержание урока</h2> +<ol> + <li><a href="#DetermineChargeState">Определение текущего состояния зарядки</a></li> + <li><a href="#MonitorChargeState">Отслеживание изменений состояния зарядки</a></li> + <li><a href="#CurrentLevel">Определение текущего уровня заряда батареи</a></li> + <li><a href="#MonitorLevel">Отслеживание существенных изменений уровня заряда батареи</a></li> +</ol> + +<h2>Дополнительные материалы</h2> +<ul> + <li><a href="{@docRoot}guide/components/intents-filters.html">Намерения и фильтры намерений</a> +</ul> + +</div> +</div> + +<p>Если вы хотите изменить частоту фоновых обновлений, чтобы продлить время работы устройства от батареи, сначала рекомендуется проверить текущий уровень заряда и состояние зарядки.</p> + +<p>Именно от этих двух факторов зависит, как обновления повлияют на время работы устройства от батареи. Когда устройство подключено к сети переменного тока, приложение можно обновлять максимально часто, поскольку процесс обновления не будет сказываться на уровне заряда батареи. Если устройство не подключено к сети, следует воздержаться от обновлений, чтобы продлить время его работы от батареи.</p> + +<p>Если заряд батареи практически исчерпан, можно снизить частоту обновлений (вплоть до их полного прекращения).</p> + + +<h2 id="DetermineChargeState">Определение текущего состояния зарядки</h2> + +<p>Начните с определения текущего состояния зарядки. {@link android.os.BatteryManager} передает все сведения о батарее и зарядке в закрепленном намерении {@link android.content.Intent}, которое содержит также информацию о состоянии зарядки.</p> + +<p>Поскольку это намерение является закрепленным, регистрировать {@link android.content.BroadcastReceiver} не нужно. Чтобы получить текущее состояние батареи в виде намерения, нужно вызвать {@code registerReceiver}, передав {@code null} в качестве приемника, как показано в коде ниже. Можно также передать фактический объект {@link android.content.BroadcastReceiver}, но это необязательно, поскольку обработка обновлений будет выполняться позднее.</p> + +<pre>IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); +Intent batteryStatus = context.registerReceiver(null, ifilter);</pre> + +<p>Можно извлечь данные как о текущем состоянии, так и об источнике зарядки (USB или сеть переменного тока), если устройство заряжается:<p> + +<pre>// Are we charging / charged? +int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1); +boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || + status == BatteryManager.BATTERY_STATUS_FULL; + +// How are we charging? +int chargePlug = battery.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); +boolean usbCharge = chargePlug == BATTERY_PLUGGED_USB; +boolean acCharge = chargePlug == BATTERY_PLUGGED_AC;</pre> + +<p>Как правило, если устройство подключено к сети переменного тока, фоновые обновления можно выполнять с максимальной частотой. Если устройство заряжается через USB, частоту можно несколько сократить, а если устройство не подключено к сети – сократить еще больше.</p> + + +<h2 id="MonitorChargeState">Отслеживание изменений состояния зарядки</h2> + +<p>Состояние зарядки изменяется всякий раз, когда пользователь подключает устройство к источнику питания. Поскольку это случается довольно часто, важно отслеживать изменения этого состояния и соответствующим образом корректировать частоту обновления приложения.</p> + +<p>{@link android.os.BatteryManager} передает действие каждый раз, когда устройство подключается к источнику питания или отключается от него. Важно получать эти события, даже если приложение не работает. Они помогут, в частности, определить, как часто будет запускаться приложение для выполнения фоновых обновлений. Чтобы отслеживать их, зарегистрируйте {@link android.content.BroadcastReceiver} в манифесте, задав {@link android.content.Intent#ACTION_POWER_CONNECTED} и {@link android.content.Intent#ACTION_POWER_DISCONNECTED} в фильтре намерений.</p> + +<pre><receiver android:name=".PowerConnectionReceiver"> + <intent-filter> + <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/> + <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/> + </intent-filter> +</receiver></pre> + +<p>Соответствующая реализация {@link android.content.BroadcastReceiver} позволяет извлечь данные о текущем состоянии и способе зарядки, как описано в предыдущем шаге.</p> + +<pre>public class PowerConnectionReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1); + boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || + status == BatteryManager.BATTERY_STATUS_FULL; + + int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); + boolean usbCharge = chargePlug == BATTERY_PLUGGED_USB; + boolean acCharge = chargePlug == BATTERY_PLUGGED_AC; + } +}</pre> + + +<h2 id="CurrentLevel">Определение текущего уровня заряда батареи</h2> + +<p>В некоторых случаях целесообразно определять текущий уровень заряда батареи. Если он ниже определенного значения, частоту фоновых обновлений следует уменьшить.</p> + +<p>Узнать, каков в настоящий момент заряд батареи, можно путем извлечения данных о текущем и максимальном уровне заряда из намерения состояния батареи, как показано в этом коде:</p> + +<pre>int level = battery.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); +int scale = battery.getIntExtra(BatteryManager.EXTRA_SCALE, -1); + +float batteryPct = level / (float)scale;</pre> + + +<h2 id="MonitorLevel">Отслеживание существенных изменений уровня заряда батареи</h2> + +<p>Отслеживать состояние батареи непрерывно не следует,</p> + +<p>поскольку при этом нагрузка на батарею будет значительно выше, чем при обычной работе приложения. Рекомендуется отслеживать только существенные изменения уровня заряда, в частности, переход устройства в состояние низкого заряда и обратно.</p> + +<p>Фрагмент манифеста, приведенный ниже, относится к фильтру намерений в приемнике широковещательных намерений. Приемник срабатывает, когда батарея устройства переходит в состояние низкого заряда или выходит из него. Для этого прослушиваются события {@link android.content.Intent#ACTION_BATTERY_LOW} и {@link android.content.Intent#ACTION_BATTERY_OKAY}.</p> + +<pre><receiver android:name=".BatteryLevelReceiver"> +<intent-filter> + <action android:name="android.intent.action.ACTION_BATTERY_LOW"/> + <action android:name="android.intent.action.ACTION_BATTERY_OKAY"/> + </intent-filter> +</receiver></pre> + +<p>Общепринятой практикой является отключение всех фоновых обновлений, когда заряд батареи достигает критически низкого уровня. Будет уже неважно, насколько актуальны данные в вашем приложении, если телефон самопроизвольно выключится, прежде чем пользователь успеет их просмотреть.</p> + +<p>Во многих случаях начало зарядки устройства совпадает с моментом его установки в док-станцию. В следующем уроке описаны способы определения текущего состояния подключения устройства к док-станции и отслеживания изменений этого состояния.</p> + diff --git a/docs/html-intl/ru/training/monitoring-device-state/connectivity-monitoring.jd b/docs/html-intl/ru/training/monitoring-device-state/connectivity-monitoring.jd new file mode 100644 index 0000000..ca1a942 --- /dev/null +++ b/docs/html-intl/ru/training/monitoring-device-state/connectivity-monitoring.jd @@ -0,0 +1,70 @@ +page.title=Determining and Monitoring the Connectivity Status +parent.title=Optimizing Battery Life +parent.link=index.html + +trainingnavtop=true + +previous.title=Determining and Monitoring the Docking State and Type +previous.link=docking-monitoring.html +next.title=Manipulating Broadcast Receivers On Demand +next.link=manifest-receivers.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>Содержание урока</h2> +<ol> + <li><a href="#DetermineConnection">Определение наличия подключения к Интернету</a></li> + <li><a href="#DetermineType">Определение типа подключения к Интернету</a></li> + <li><a href="#MonitorChanges">Отслеживание изменения возможностей подключения</a></li> +</ol> + + +<h2>Дополнительные материалы</h2> +<ul> + <li><a href="{@docRoot}guide/components/intents-filters.html">Намерения и фильтры намерений</a> +</ul> + +</div> +</div> + +<p>Чаще всего повторяющиеся оповещения и фоновые службы используются для планового обновления приложения из Интернета, кэширования или загрузки больших объемов данных. Однако если подключение к Интернету не установлено или скорость соединения слишком низкая, выполнять загрузку не имеет смысла.</p> + +<p>Проверить наличие подключения к Интернету и его тип можно с помощью {@link android.net.ConnectivityManager}.</p> + + +<h2 id="DetermineConnection">Определение наличия подключения к Интернету</h2> + +<p>Если подключение отсутствует, нет смысла планировать обновление из Интернета. В приведенном ниже коде показано, как использовать {@link android.net.ConnectivityManager} для отправки запросов об активной сети и определять возможности подключения.</p> + +<pre>ConnectivityManager cm = + (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); + +NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); +boolean isConnected = activeNetwork.isConnectedOrConnecting();</pre> + + +<h2 id="DetermineType">Определение типа подключения к Интернету</h2> + +<p>Также можно определить тип доступного в настоящий момент подключения к Интернету.</p> + +<p>Устройство может подключаться по сети мобильной связи, WiMAX, Wi-Fi и Ethernet. Получив ответ на запрос о типе активной сети, как показано ниже, можно изменить частоту обновлений на основе ее пропускной способности.</p> + +<pre>boolean isWiFi = activeNetwork.getType() == ConnectivityManager.TYPE_WIFI;</pre> + +<p>Стоимость передачи данных по мобильной сети, как правило, значительно выше, чем по сети Wi-Fi, поэтому частота обновлений в первом случае должна быть ниже. То же касается загрузки большого количества данных: ее следует отложить, пока не будет установлено подключение к сети Wi-Fi.</p> + +<p>Когда обновления отключены, необходимо отслеживать изменения доступных соединений, чтобы возобновить их сразу после подключения устройства к Интернету.</p> + + +<h2 id="MonitorChanges">Отслеживание изменения возможностей подключения</h2> + +<p>{@link android.net.ConnectivityManager} передает действие {@link android.net.ConnectivityManager#CONNECTIVITY_ACTION} ({@code "android.net.conn.CONNECTIVITY_CHANGE"}) при каждом изменении сведений о подключении. Зарегистрируйте в манифесте приемник широковещательных намерений, чтобы отслеживать эти изменения и запускать (или приостанавливать) фоновые обновления соответствующим образом.</p> + +<pre><action android:name="android.net.conn.CONNECTIVITY_CHANGE"/></pre> + +<p>Доступные соединения могут меняться очень часто – эта передача инициируется при каждом переключении между сетью мобильной связи и Wi-Fi. Ее рекомендуется отслеживать, только когда необходимо запускать ранее приостановленные обновления или загрузки. Как правило, достаточно проверить наличие подключения к Интернету перед запуском обновления и, если оно отсутствует, приостановить дальнейшие обновления до восстановления соединения.</p> + +<p>Для использования этого метода необходимо включать и отключать приемники широковещательных намерений, объявленные в манифесте. В следующем уроке описано, как это делать.</p> diff --git a/docs/html-intl/ru/training/monitoring-device-state/docking-monitoring.jd b/docs/html-intl/ru/training/monitoring-device-state/docking-monitoring.jd new file mode 100644 index 0000000..d94f357 --- /dev/null +++ b/docs/html-intl/ru/training/monitoring-device-state/docking-monitoring.jd @@ -0,0 +1,74 @@ +page.title=Determining and Monitoring the Docking State and Type +parent.title=Optimizing Battery Life +parent.link=index.html + +trainingnavtop=true +previous.title= Monitoring the Battery Level and Charging State +previous.link=battery-monitoring.html +next.title= Determining and Monitoring the Connectivity Status +next.link=connectivity-monitoring.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>Содержание урока</h2> +<ol> + <li><a href="#CurrentDockState">Запрос аудиофокуса</a></li> + <li><a href="#DockType">Определение типа док-станции</a></li> + <li><a href="#MonitorDockState">Отслеживание изменений состояния подключения к док-станции и ее типа</a></li> +</ol> + + +<h2>Дополнительные материалы</h2> +<ul> + <li><a href="{@docRoot}guide/components/intents-filters.html">Намерения и фильтры намерений</a> +</ul> + +</div> +</div> + +<p>Устройства под управлением ОС Android можно подключать к нескольким типам док-станций: настольным, которые делятся на цифровые и аналоговые, и автомобильным. В большинстве случаев устройства заряжаются при подключении к док-станции, поэтому состояние подключения к док-станции часто связано с состоянием зарядки.</p> + +<p>Насколько состояние подключения к док-станции влияет на частоту обновления, зависит от конкретного приложения. Например, можно увеличить частоту обновлений приложения, показывающего спортивные новости, когда устройство подключено к настольной док-станции, и полностью отключить обновления при подключении к автомобильной. И наоборот, если используется приложение, которое в фоновом режиме загружает данные о дорожной обстановке, то при подключении устройства к автомобильной док-станции следует выполнять обновления максимально часто.</p> + +<p>Состояние подключения к док-станции также передается в виде закрепленного намерения {@link android.content.Intent}, что позволяет запрашивать сведения о наличии подключения к док-станции и ее типе.</p> + + +<h2 id="CurrentDockState">Определение текущего состояния подключения к док-станции</h2> + +<p>Сведения о состоянии подключения к док-станции передаются в качестве дополнительных данных в закрепленном оповещении действия {@link android.content.Intent#ACTION_DOCK_EVENT}. Поскольку это закрепленное намерение, регистрировать {@link android.content.BroadcastReceiver} не требуется. Достаточно вызвать {@link android.content.Context#registerReceiver registerReceiver()}, передав {@code null} в качестве приемника широковещательных намерений, как показано в коде ниже.</p> + +<pre>IntentFilter ifilter = new IntentFilter(Intent.ACTION_DOCK_EVENT); +Intent dockStatus = context.registerReceiver(null, ifilter);</pre> + +<p>Сведения о текущем состоянии подключения к док-станции можно извлечь из дополнительных данных {@code EXTRA_DOCK_STATE}:<p> + +<pre>int dockState = battery.getIntExtra(EXTRA_DOCK_STATE, -1); +boolean isDocked = dockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;</pre> + + +<h2 id="DockType">Определение типа док-станции</h2> + +<p>Док-станция, к которой подключено устройство, может быть одного из четырех типов: +<ul><li>автомобильная;</li> +<li>настольная;</li> +<li>настольная с минимальным набором функций (аналоговая);</li> +<li>настольная с широким набором функций (цифровая).</li></ul></p> + +<p>Обратите внимание, что последние два типа поддерживаются только на уровне API 11, поэтому, даже если вас не интересует, является ли док-станция цифровой или аналоговой, а интересует только ее тип, рекомендуется выполнять проверку по всем трем типам:</p> + +<pre>boolean isCar = dockState == EXTRA_DOCK_STATE_CAR; +boolean isDesk = dockState == EXTRA_DOCK_STATE_DESK || + dockState == EXTRA_DOCK_STATE_LE_DESK || + dockState == EXTRA_DOCK_STATE_HE_DESK;</pre> + + +<h2 id="MonitorDockState">Отслеживание изменений состояния подключения к док-станции и ее типа</h2> + +<p>При каждом подключении устройства к док-станции или отключении от нее передается действие {@link android.content.Intent#ACTION_DOCK_EVENT}. Чтобы отслеживать состояние подключения к док-станции, достаточно зарегистрировать в манифесте приложения приемник широковещательных намерений, как показано ниже.</p> + +<pre><action android:name="android.intent.action.ACTION_DOCK_EVENT"/></pre> + +<p>Данные о типе док-станции и о состоянии подключения к ней можно извлечь внутри реализации приемника с помощью методов, описанных в предыдущем шаге.</p> diff --git a/docs/html-intl/ru/training/monitoring-device-state/index.jd b/docs/html-intl/ru/training/monitoring-device-state/index.jd new file mode 100644 index 0000000..c87d9af --- /dev/null +++ b/docs/html-intl/ru/training/monitoring-device-state/index.jd @@ -0,0 +1,49 @@ +page.title=Optimizing Battery Life + +trainingnavtop=true +startpage=true +next.title=Monitoring the Battery Level and Charging State +next.link=battery-monitoring.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>Требования</h2> +<ul> + <li>Android 2.0 (API уровня 5) или более поздней версии</li> + <li>Опыт работы с <a href="{@docRoot}guide/components/intents-filters.html">намерениями и фильтрами намерений</a></li> +</ul> + +<h2>Дополнительные материалы</h2> +<ul> + <li><a href="{@docRoot}guide/components/services.html">Службы</a> +</ul> + +</div> +</div> + +<p>Качественное приложение должно оказывать минимальное влияние на время работы устройства от батареи. В этом уроке вы научитесь создавать приложения, способные изменять функционал и режим работы в зависимости от состояния устройства.</p> + +<p>Отключение обновления данных фоновых служб при потере подключения и снижение частоты обновления при низком заряде батареи позволяет снизить расход энергии и продлить работу устройства без подзарядки.</p> + +<h2>Уроки</h2> + +<!-- Create a list of the lessons in this class along with a short description of each lesson. +These should be short and to the point. It should be clear from reading the summary whether someone +will want to jump to a lesson or not.--> + +<dl> + <dt><b><a href="battery-monitoring.html">Отслеживание уровня заряда батареи и состояния зарядки</a></b></dt> + <dd>Вы узнаете, как изменять частоту обновления приложения, определяя и отслеживая текущий уровень заряда батареи и изменение состояния зарядки.</dd> + + <dt><b><a href="docking-monitoring.html">Отслеживание состояния подключения к док-станции и определение ее типа</a></b></dt> + <dd>Оптимальная частота обновления зависит от способа использования устройства. Вы узнаете, как определять и отслеживать состояние подключения к док-станции и ее тип, чтобы соответствующим образом корректировать работу приложения.</dd> + + <dt><b><a href="connectivity-monitoring.html">Определение и отслеживание состояния подключения</a></b></dt> + <dd>Приложение невозможно обновить через Интернет, если отсутствует подключение. Вы узнаете, как проверить состояние подключения, чтобы при необходимости изменить частоту фоновых обновлений. Также вы научитесь проверять наличие мобильного подключения или подключения по сети Wi-Fi перед началом операций, требующих передачи больших объемов данных.</dd> + + <dt><b><a href="manifest-receivers.html">Операции с приемниками широковещательных намерений по запросу</a></b></dt> + <dd>Приемники широковещательных намерений, объявленные в манифесте, можно включать и отключать во время работы приложения. Это позволяет отключать ненужные приемники в зависимости от состояния устройства. Вы узнаете, как повысить эффективность путем включения, отключения или каскадирования приемников изменения состояния и как отложить действие до момента перехода устройства в заданное состояние.</dd> +</dl>
\ No newline at end of file diff --git a/docs/html-intl/ru/training/monitoring-device-state/manifest-receivers.jd b/docs/html-intl/ru/training/monitoring-device-state/manifest-receivers.jd new file mode 100644 index 0000000..724ee93 --- /dev/null +++ b/docs/html-intl/ru/training/monitoring-device-state/manifest-receivers.jd @@ -0,0 +1,50 @@ +page.title=Manipulating Broadcast Receivers On Demand +parent.title=Optimizing Battery Life +parent.link=index.html + +trainingnavtop=true + +previous.title=Determining and Monitoring the Connectivity Status +previous.link=connectivity-monitoring.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>Содержание урока</h2> +<ol> + <li><a href="#ToggleReceivers">Включение, отключение и каскадирование приемников изменения состояния для повышения эффективности</a></li> +</ol> + + +<h2>Дополнительные материалы</h2> +<ul> + <li><a href="{@docRoot}guide/components/intents-filters.html">Намерения и фильтры намерений</a> +</ul> + +</div> +</div> + +<p>Самый простой способ отслеживать изменения состояния устройства – создать приемники {@link android.content.BroadcastReceiver} для каждого отслеживаемого состояния и зарегистрировать их в манифесте приложения. Затем в каждом из этих приемников можно переопределять график повторяющихся оповещений в зависимости от текущего состояния устройства.</p> + +<p>Этот способ имеет недостатки: приложение активирует устройство при каждом запуске любого из этих приемников, что далеко не всегда оправданно.</p> + +<p>Оптимальный вариант – включать и выключать приемники широковещательных намерений во время работы приложения. Это позволяет использовать приемники, объявленные в манифесте, как пассивные оповещения, которые инициируются системными событиями только в случае необходимости.</p> + + +<h2 id="ToggleReceivers">Включение, отключение и каскадирование приемников изменения состояния для повышения эффективности </h2> + +<p>{@link android.content.pm.PackageManager} позволяет включать и выключать любые компоненты, определенные в манифесте, в том числе все приемники широковещательных намерений:</p> + +<pre>ComponentName receiver = new ComponentName(context, myReceiver.class); + +PackageManager pm = context.getPackageManager(); + +pm.setComponentEnabledSetting(receiver, + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP)</pre> + +<p>При разрыве соединения этот метод позволяет выключить все приемники, кроме приемника изменения состояния подключения. И наоборот, когда подключение уже установлено, отслеживать изменения его состояния не требуется. Достаточно проверить наличие подключения к Интернету непосредственно перед обновлением или изменением графика оповещений о регулярном обновлении.</p> + +<p>Точно так же можно отложить загрузку, для выполнения которой требуется более высокая пропускная способность. Просто включите приемник широковещательных намерений, который будет отслеживать изменения возможности подключения и инициировать загрузку только после подключения к сети Wi-Fi.</p> diff --git a/docs/html-intl/ru/training/multiscreen/adaptui.jd b/docs/html-intl/ru/training/multiscreen/adaptui.jd new file mode 100644 index 0000000..490a64a --- /dev/null +++ b/docs/html-intl/ru/training/multiscreen/adaptui.jd @@ -0,0 +1,212 @@ +page.title=Implementing Adaptative UI Flows +parent.title=Designing for Multiple Screens +parent.link=index.html + +trainingnavtop=true +previous.title=Supporting Different Screen Densities +previous.link=screendensities.html + +@jd:body + + +<!-- This is the training bar --> +<div id="tb-wrapper"> +<div id="tb"> + +<h2>Содержание урока</h2> + +<ol> + <li><a href="#TaskDetermineCurLayout">Определение текущего макета</a></li> + <li><a href="#TaskReactToLayout">Дальнейшие действия в зависимости от текущего макета</a></li> + <li><a href="#TaskReuseFrag">Повторное использование фрагментов в других активностях</a></li> + <li><a href="#TaskHandleConfigChanges">Обработка изменений конфигурации экрана</a></li> +</ol> + +<h2>Дополнительные материалы</h2> + +<ul> + <li><a href="{@docRoot}guide/practices/tablets-and-handsets.html">Поддержка планшетных ПК и мобильных телефонов</a></li> +</ul> + +<h2>Упражнение</h2> + +<div class="download-box"> +<a href="http://developer.android.com/shareables/training/NewsReader.zip" class="button">Загрузить учебное приложение</a> +<p class="filename">NewsReader.zip</p> +</div> + + +</div> +</div> + +<p>Алгоритм пользовательского интерфейса зависит от макета, который в данный момент отображается. Например, если приложение работает в двухпанельном режиме, то при нажатии на элемент в левой панели содержание отобразится в правой. В однопанельном режиме содержание откроется отдельно (в другой активности).</p> + + +<h2 id="TaskDetermineCurLayout">Определение текущего макета</h2> + +<p>Так как в реализации макетов существуют отличия, первое, что необходимо сделать, – определить, какой макет отображается в данный момент. Например, работает ли приложение в однопанельном или двухпанельном режиме. Для этого создадим запрос о том, существует ли данное представление и отображается ли оно в настоящий момент:</p> + +<pre class="prettyprint"> +public class NewsReaderActivity extends FragmentActivity { + boolean mIsDualPane; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main_layout); + + View articleView = findViewById(R.id.article); + mIsDualPane = articleView != null && + articleView.getVisibility() == View.VISIBLE; + } +} +</pre> + +<p>Обратите внимание: представленный выше код содержит запрос о том, доступна ли панель article, поскольку это удобнее, чем писать отдельные запросы для каждого макета.</p> + +<p>Кроме того, для работы с учетом существующих компонентов можно также проверять их доступность, прежде чем выполнять с ними какие-либо операции. Например, в учебном приложении News Reader есть кнопка, которая служит для доступа в меню, однако она отображается только в операционных системах Android версии ниже, чем 3.0, потому что в последующих версиях ее функцию выполняет элемент <PH>{@link android.app.ActionBar}</PH> на уровне API 11 и выше. Чтобы проверить наличие этой кнопки, добавим прослушиватель событий с помощью следующего кода:</p> + +<pre class="prettyprint"> +Button catButton = (Button) findViewById(R.id.categorybutton); +OnClickListener listener = /* create your listener here */; +if (catButton != null) { + catButton.setOnClickListener(listener); +} +</pre> + + +<h2 id="TaskReactToLayout">Дальнейшие действия в зависимости от текущего макета</h2> + +<p>Результаты некоторых операций зависят от текущего макета. Например, если в приложении News Reader в двухпанельном режиме нажать на заголовок в списке, то статья откроется в правой панели. Если же интерфейс работает в однопанельном режиме, будет запущена отдельная активность:</p> + +<pre> +@Override +public void onHeadlineSelected(int index) { + mArtIndex = index; + if (mIsDualPane) { + /* display article on the right pane */ + mArticleFragment.displayArticle(mCurrentCat.getArticle(index)); + } else { + /* start a separate activity */ + Intent intent = new Intent(this, ArticleActivity.class); + intent.putExtra("catIndex", mCatIndex); + intent.putExtra("artIndex", index); + startActivity(intent); + } +} +</pre> + +<p>Аналогично, в двухпанельном режиме должна отображаться панель действий с навигационными вкладками, а в однопанельном навигация должна быть реализована с помощью раскрывающегося списка. Приложение должно проверять, какой из этих вариантов следует использовать:</p> + +<pre> +final String CATEGORIES[] = { "Лучшие статьи", "Политика", "Экономика", "Новости технологий" }; + +public void onCreate(Bundle savedInstanceState) { + .... + if (mIsDualPane) { + /* use tabs for navigation */ + actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_TABS); + int i; + for (i = 0; i < CATEGORIES.length; i++) { + actionBar.addTab(actionBar.newTab().setText( + CATEGORIES[i]).setTabListener(handler)); + } + actionBar.setSelectedNavigationItem(selTab); + } + else { + /* use list navigation (spinner) */ + actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_LIST); + SpinnerAdapter adap = new ArrayAdapter<String>(this, + R.layout.headline_item, CATEGORIES); + actionBar.setListNavigationCallbacks(adap, handler); + } +} +</pre> + + +<h2 id="TaskReuseFrag">Повторное использование фрагментов в других активностях</h2> + +<p>Одним из примеров повторяющегося фрагмента является реализация части интерфейса как панели в одних конфигурациях и как отдельной активности в других. Например, если приложение News Reader работает на достаточно большом экране, текст новостной статьи отображается в правой панели, а если на маленьком, то он открывается в отдельной активности.</p> + +<p>В таких случаях следует повторно использовать подкласс <PH>{@link android.app.Fragment}</PH> в нескольких активностях. Например, в двухпанельном макете используется подкласс <code>ArticleFragment</code>:</p> + +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all} + +<p>Он же (без макета) используется при работе на маленьком экране (активность <code>ArticleActivity</code>):</p> + +<pre> +ArticleFragment frag = new ArticleFragment(); +getSupportFragmentManager().beginTransaction().add(android.R.id.content, frag).commit(); +</pre> + +<p>Результат будет таким же, как если бы мы объявили фрагмент в макете XML, однако в этом случае макет XML не требуется, так как фрагмент article является единственным компонентом этой активности.</p> + +<p>При создании фрагментов важно не привязывать их строго к конкретной активности. Для этого можно определить интерфейс с абстрактным описанием всех необходимых способов взаимодействия фрагмента с активностью, в которой он содержится. Затем этот интерфейс нужно реализовать в самой активности.</p> + +<p>Например, именно так работает фрагмент <code>HeadlinesFragment</code> в приложении News Reader:</p> + +<pre> +public class HeadlinesFragment extends ListFragment { + ... + OnHeadlineSelectedListener mHeadlineSelectedListener = null; + + /* Must be implemented by host activity */ + public interface OnHeadlineSelectedListener { + public void onHeadlineSelected(int index); + } + ... + + public void setOnHeadlineSelectedListener(OnHeadlineSelectedListener listener) { + mHeadlineSelectedListener = listener; + } +} +</pre> + +<p>Затем, когда пользователь выбирает заголовок, фрагмент оповещает об этом не указанную в коде активность, а заданный ею прослушиватель:</p> + +<pre> +public class HeadlinesFragment extends ListFragment { + ... + @Override + public void onItemClick(AdapterView<?> parent, + View view, int position, long id) { + if (null != mHeadlineSelectedListener) { + mHeadlineSelectedListener.onHeadlineSelected(position); + } + } + ... +} +</pre> + +<p>Этот метод рассматривается подробнее в разделе <a +href="{@docRoot}guide/practices/tablets-and-handsets.html">Поддержка планшетных ПК и мобильных телефонов</a>.</p> + + +<h2 id="TaskHandleConfigChanges">Обработка изменений конфигурации экрана</h2> + +<p>При реализации отдельных частей интерфейса с помощью разных активностей нужно учитывать, что интерфейс должен уметь реагировать на определенные изменения конфигурации, такие как поворот экрана.</p> + +<p>Например, на типичном планшетном ПК с размером экрана 7 дюймов под управлением ОС Android 3.0 или более поздней версии при вертикальной ориентации статья в приложении News Reader открывается с помощью отдельной активности, а при горизонтальной используется двухпанельный макет.</p> + +<p>Это означает, что если пользователь держит планшетный ПК вертикально и на экране запущена активность для просмотра статьи, приложение должно уметь определить, что ориентация была изменена на горизонтальную. Затем оно должно соответствующим образом отреагировать на изменение, то есть завершить эту активность и вернуться к основной активности, чтобы содержание отобразилось в двухпанельном макете:</p> + +<pre> +public class ArticleActivity extends FragmentActivity { + int mCatIndex, mArtIndex; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mCatIndex = getIntent().getExtras().getInt("catIndex", 0); + mArtIndex = getIntent().getExtras().getInt("artIndex", 0); + + // If should be in two-pane mode, finish to return to main activity + if (getResources().getBoolean(R.bool.has_two_panes)) { + finish(); + return; + } + ... +} +</pre> + + diff --git a/docs/html-intl/ru/training/multiscreen/index.jd b/docs/html-intl/ru/training/multiscreen/index.jd new file mode 100644 index 0000000..023eaec --- /dev/null +++ b/docs/html-intl/ru/training/multiscreen/index.jd @@ -0,0 +1,64 @@ +page.title=Designing for Multiple Screens + +trainingnavtop=true +startpage=true +next.title=Supporting Different Screen Sizes +next.link=screensizes.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>Требования</h2> + +<ul> + <li>Android 1.6 или более поздней версии (для запуска учебного приложения требуется версия 2.1 или более поздняя)</li> + <li>Начальные знания о компонентах <a +href="http://developer.android.com/guide/components/activities.html">Activity</a> (активность) и <a href="http://developer.android.com/guide/components/fragments.html">Fragment</a> (фрагмент)</li> + <li>Опыт создания <a +href="http://developer.android.com/guide/topics/ui/index.html">пользовательских интерфейсов</a> для Android</li> + <li>Некоторые функции требуют использования <a +href="{@docRoot}tools/extras/support-library.html">вспомогательной библиотеки</a></li> +</ul> + +<h2>Дополнительные материалы</h2> + +<ul> + <li><a href="{@docRoot}guide/practices/screens_support.html">Поддержка нескольких экранов</a></li> +</ul> + +<h2>Упражнение</h2> + +<div class="download-box"> +<a href="http://developer.android.com/shareables/training/NewsReader.zip" class="button">Загрузить учебное приложение</a> +<p class="filename">NewsReader.zip</p> +</div> + +</div> +</div> + +<p>На платформе Android работают устройства с самыми разными размерами экрана: от телефонов до телевизоров. Чтобы с вашим приложением могли работать как можно больше пользователей, оно должно корректно отображаться на всех этих устройствах.</p> + +<p>Однако совместимость с разными типами устройств – это еще не все. От размера экрана зависит, какие возможности будет иметь пользователь при работе с приложением. Чтобы пользователи действительно остались довольны вашим приложением, оно должно не просто <em>поддерживать</em> разные экраны, но и быть <em>оптимизировано</em> для каждого из них.</p> + +<p>Этот модуль посвящен реализации пользовательского интерфейса, оптимизированного для разных конфигураций экрана.</p> + +<p>Код, приведенный в каждом уроке, взят из учебного приложения, в котором демонстрируются способы оптимизации для разных экранов. Вы можете загрузить его (в правой части экрана) и использовать части кода в собственном приложении.</p> + +<p class="note"><strong>Примечание</strong>. В этом модуле и в учебном приложении используется <a +href="{@docRoot}tools/extras/support-library.html">вспомогательная библиотека</a>, позволяющая работать с API <PH>{@link android.app.Fragment}</PH> в версиях до Android 3.0. Чтобы иметь возможность использовать все необходимые API, загрузите библиотеку и добавьте ее в свое приложение.</p> + + +<h2>Уроки</h2> + +<dl> + <dt><b><a href="screensizes.html">Поддержка разных размеров экрана</a></b></dt> + <dd>В этом уроке рассказывается, как создать макет, который адаптируется к разным размерам экрана, используя масштабируемые представления, объекты <PH>{@link android.widget.RelativeLayout}</PH>, квалификаторы размера и ориентации, фильтры псевдонимов и растровые изображений формата nine-patch.</dd> + + <dt><b><a href="screendensities.html">Поддержка разных разрешений экрана</a></b></dt> + <dd>В этом уроке рассказывается, как работать с экранами разного разрешения с помощью не зависящих от разрешения пикселей и как подготовить растровые изображения для каждого из них.</dd> + + <dt><b><a href="adaptui.html">Реализация адаптируемых алгоритмов работы пользовательского интерфейса</a></b></dt> + <dd>В этом уроке рассказывается, как реализовать алгоритм работы интерфейса, адаптирующийся к размеру и разрешению экрана, то есть способный определять активный макет во время выполнения приложения, выбирать дальнейшие действия на основе текущего макета и обрабатывать изменения конфигурации экрана.</dd> +</dl> diff --git a/docs/html-intl/ru/training/multiscreen/screendensities.jd b/docs/html-intl/ru/training/multiscreen/screendensities.jd new file mode 100644 index 0000000..cfd4724 --- /dev/null +++ b/docs/html-intl/ru/training/multiscreen/screendensities.jd @@ -0,0 +1,100 @@ +page.title=Supporting Different Densities +parent.title=Designing for Multiple Screens +parent.link=index.html + +trainingnavtop=true +previous.title=Supporting Different Screen Sizes +previous.link=screensizes.html +next.title=Implementing Adaptative UI Flows +next.link=adaptui.html + +@jd:body + + +<!-- This is the training bar --> +<div id="tb-wrapper"> +<div id="tb"> + +<h2>Содержание урока</h2> +<ol> + <li><a href="#TaskUseDP">Использование пикселей, не зависящих от разрешения</a></li> + <li><a href="#TaskProvideAltBmp">Предоставление альтернативных растровых изображений</a></li> +</ol> + +<h2>Дополнительные материалы</h2> + +<ul> + <li><a href="{@docRoot}guide/practices/screens_support.html">Поддержка нескольких экранов</a></li> + <li><a href="{@docRoot}guide/practices/ui_guidelines/icon_design.html">Рекомендации по созданию значков</a></li> +</ul> + +<h2>Упражнение</h2> + +<div class="download-box"> +<a href="http://developer.android.com/shareables/training/NewsReader.zip" class="button">Загрузить учебное приложение</a> +<p class="filename">NewsReader.zip</p> +</div> + + +</div> +</div> + +<p>В этом уроке рассказывается, как создать интерфейс, поддерживающий разные разрешения экрана, за счет использования разных ресурсов и не зависящих от разрешения единиц измерения.</p> + +<h2 id="TaskUseDP">Использование пикселей, не зависящих от разрешения</h2> + +<p>Разработчики часто допускают одну и ту же ошибку при создании макетов – указывают размеры и расстояния с помощью абсолютных значений в пикселях. Задавать размеры в пикселях не рекомендуется, поскольку из-за различной плотности пикселей на экранах разных устройств фактический размер макета будет неодинаков. Всегда задавайте размеры в единицах <code>dp</code> или <code>sp</code>. <code>dp</code> – это не зависящий от разрешения пиксель, равный физическому пикселю на экране с плотностью 160 точек/дюйм. <code>sp</code> является аналогичной единицей измерения, но масштабируется на основе выбранного пользователем размера текста, поэтому ее следует применять для указания величины шрифта, но не размера макета.</p> + +<p>Например, если вы задаете расстояние между двумя представлениями, рекомендуется использовать <code>dp</code>, а не <code>px</code>:</p> + +<pre> +<Button android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/clickme" + android:layout_marginTop="20dp" /> +</pre> + +<p>Для определения размера шрифта всегда используйте <code>sp</code>:</p> + +<pre> +<TextView android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="20sp" /> +</pre> + + +<h2 id="TaskProvideAltBmp">Предоставление альтернативных растровых изображений</h2> + +<p>Так как платформа Android предназначена для устройств с разными разрешениями экрана, необходимо позаботиться о наличии растровых изображений для каждого из четырех обобщенных типов разрешения: низкого, среднего, высокого и очень высокого. Это обеспечит оптимальное сочетание качества графики и производительности на всех устройствах.</p> + +<p>На основе исходного векторного рисунка создайте растровые изображения для каждого из указанных разрешений согласно следующей шкале размеров:</p> + +<p><ul> + <li><code>xhdpi</code>: 2,0 + <li><code>hdpi</code>: 1,5 + <li><code>mdpi</code>: 1,0 (стандартный размер) + <li><code>ldpi</code>: 0,75 +</ul></p> + +<p>Это означает, что изображение, которое на устройствах с разрешением экрана <code>xhdpi</code> имеет размер 200 x 200, на устройствах <code>hdpi</code> должно иметь размер 150 x 150, на устройствах <code>mdpi</code> – 100 x 100, а на устройствах <code>ldpi</code> – 75 x 75.</p> + +<p>Поместите файлы изображений в соответствующие подкаталоги в папке <code>res/</code>, и система автоматически выберет подходящий в зависимости от разрешения экрана устройства, на котором выполняется приложение:</p> + +<pre class="classic no-pretty-print"> +MyProject/ + res/ + drawable-xhdpi/ + awesomeimage.png + drawable-hdpi/ + awesomeimage.png + drawable-mdpi/ + awesomeimage.png + drawable-ldpi/ + awesomeimage.png +</pre> + +<p>При каждом обращении к файлу <code>@drawable/awesomeimage</code> система будет выбирать изображение, отвечающее разрешению экрана.</p> + +<p>Дополнительную информацию и советы можно найти в разделе <a +href="{@docRoot}guide/practices/ui_guidelines/icon_design.html">Рекомендации по созданию значков</a>.</p> + diff --git a/docs/html-intl/ru/training/multiscreen/screensizes.jd b/docs/html-intl/ru/training/multiscreen/screensizes.jd new file mode 100644 index 0000000..9684d77 --- /dev/null +++ b/docs/html-intl/ru/training/multiscreen/screensizes.jd @@ -0,0 +1,279 @@ +page.title=Supporting Different Screen Sizes +parent.title=Designing for Multiple Screens +parent.link=index.html + +trainingnavtop=true +next.title=Supporting Different Screen Densities +next.link=screendensities.html + +@jd:body + + +<!-- This is the training bar --> +<div id="tb-wrapper"> +<div id="tb"> + +<h2>Содержание урока</h2> +<ol> + <li><a href="#TaskUseWrapMatchPar">Использование параметров wrap_content и match_parent</a></li> + <li><a href="#TaskUseRelativeLayout">Использование объекта RelativeLayout</a></li> + <li><a href="#TaskUseSizeQuali">Использование квалификаторов размера</a></li> + <li><a href="#TaskUseSWQuali">Использование квалификатора Smallest-width</a></li> + <li><a href="#TaskUseAliasFilters">Использование псевдонимов макетов</a></li> + <li><a href="#TaskUseOriQuali">Использование квалификаторов ориентации</a></li> + <li><a href="#TaskUse9Patch">Использование растровых изображений nine-patch</a></li> +</ol> + +<h2>Дополнительные материалы</h2> + +<ul> + <li><a href="{@docRoot}guide/practices/screens_support.html">Поддержка нескольких экранов</a></li> +</ul> + +<h2>Упражнение</h2> + +<div class="download-box"> +<a href="http://developer.android.com/shareables/training/NewsReader.zip" class="button">Загрузить учебное приложение</a> +<p class="filename">NewsReader.zip</p> +</div> + +</div> +</div> + +<p>В этом уроке описаны следующие аспекты обеспечения совместимости интерфейса с разными экранами:</p> +<ul> + <li>обеспечение способности макета адаптироваться к размеру экрана;</li> + <li>выбор макета интерфейса, отвечающего конфигурации экрана;</li> + <li>контроль правильности применяемого макета;</li> + <li>использование масштабируемых растровых изображений.</li> +</ul> + + +<h2 id="TaskUseWrapMatchPar">Использование параметров wrap_content и match_parent</h2> + +<p>Чтобы создать масштабируемый макет, способный адаптироваться к разным экранам, используйте в качестве значений ширины и высоты отдельных компонентов представления параметры <code>"wrap_content"</code> и <code>"match_parent"</code>. Если используется <code>"wrap_content"</code>, для ширины или высоты представления устанавливается минимальное значение, позволяющее уместить содержание на экран, а параметр <code>"match_parent"</code> (известный как <code>"fill_parent"</code> в API до 8 уровня) служит для растягивания компонента по размеру родительского представления.</p> + +<p>Если указать параметры <code>"wrap_content"</code> и <code>"match_parent"</code> вместо строго заданных размеров, в представлениях будет использоваться минимально необходимое место или они будут растягиваться на всю доступную длину и ширину соответственно. Например:</p> + +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane_with_bar.xml all} + +<p>Обратите внимание на то, что в коде учебного приложения размеры компонентов заданы с помощью параметров <code>"wrap_content"</code> и <code>"match_parent"</code>. В результате макет правильно отображается на экранах разных размеров при разных ориентациях.</p> + +<p>Например, вот так он выглядит в вертикальной и горизонтальной ориентациях. Обратите внимание на то, как размеры компонентов автоматически адаптируются к длине и ширине:</p> + +<img src="{@docRoot}images/training/layout-hvga.png" /> +<p class="img-caption"><strong>Рисунок 1</strong>. Приложение News Reader при вертикальной (слева) и горизонтальной (справа) ориентации.</p> + + +<h2 id="TaskUseRelativeLayout">Использование объекта RelativeLayout</h2> + +<p>С помощью вложенных экземпляров объекта <PH>{@link android.widget.LinearLayout}</PH> и параметров <code>"wrap_content"</code> и <code>"match_parent"</code> можно создавать достаточно сложные макеты. Однако <PH>{@link android.widget.LinearLayout}</PH> не дает возможности точно управлять взаимным расположением дочерних представлений: в <PH>{@link android.widget.LinearLayout}</PH> они просто помещаются в ряд друг за другом. Если необходимо расположить дочерние представления иным образом, используйте объект <PH>{@link android.widget.RelativeLayout}</PH>, позволяющий задать относительные позиции компонентов. Например, одно дочернее представление можно выровнять по левому краю экрана, а другое – по правому.</p> + +<p>Например:</p> + +<pre> +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <TextView + android:id="@+id/label" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Type here:"/> + <EditText + android:id="@+id/entry" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/label"/> + <Button + android:id="@+id/ok" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/entry" + android:layout_alignParentRight="true" + android:layout_marginLeft="10dp" + android:text="OK" /> + <Button + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toLeftOf="@id/ok" + android:layout_alignTop="@id/ok" + android:text="Cancel" /> +</RelativeLayout> +</pre> + +<p>На рис. 2 показано, как этот макет выглядит на экране QVGA.</p> + +<img src="{@docRoot}images/training/relativelayout1.png" /> +<p class="img-caption"><strong>Рисунок 2</strong>. Скриншот экрана QVGA (маленького размера).</p> + +<p>На рис. 3 показано, как он выглядит на экране с большей диагональю.</p> + +<img src="{@docRoot}images/training/relativelayout2.png" /> +<p class="img-caption"><strong>Рисунок 3</strong>. Скриншот экрана WSVGA (большего размера).</p> + +<p>Обратите внимание: несмотря на изменение размера компонентов их взаимное расположение остается прежним, так как оно задано объектом <PH>{@link android.widget.RelativeLayout.LayoutParams}</PH>.</p> + + +<h2 id="TaskUseSizeQuali">Использование квалификаторов размера</h2> + +<p>Масштабируемые или относительные макеты, один из которых продемонстрирован выше, имеют свои ограничения. Хотя они позволяют создать интерфейс, способный адаптироваться к разным экранам за счет растягивания пространства внутри и вокруг компонентов, пользователю может оказаться не слишком удобно работать с таким интерфейсом. Поэтому в приложении должен использоваться не один масштабируемый макет, а несколько альтернативных вариантов для разных конфигураций экрана. Их можно создать с помощью <a href="http://developer.android.com/guide/practices/screens_support.html#qualifiers">квалификаторов конфигураций</a>, которые позволяют оперативно выбирать ресурсы, отвечающие текущим параметрам экрана (например, разные варианты макетов для экранов разных размеров).</p> + +<p>Многие приложения отображаются на больших экранах в двухпанельном режиме, при котором список элементов расположен в одной панели, а их содержание открывается в другой. Такой режим просмотра удобен на достаточно больших экранах планшетных ПК и телевизоров, однако на экране телефона эти панели следует отображать по отдельности. Для каждого режима просмотра нужно создать отдельный файл.</p> + +<ul> + <li><code>res/layout/main.xml</code>, однопанельный макет (по умолчанию): + +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane.xml all} +</li> + <li><code>res/layout-large/main.xml</code>, двухпанельный макет: + +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all} +</li> +</ul> + +<p>Обратите внимание, что во втором случае в названии каталога использован квалификатор <code>large</code>. Этот макет будет выбран на устройствах, экраны которых считаются большими (например, 7 дюймов и более). Первый макет (без квалификаторов) будет выбран для устройств с маленьким экраном.</p> + + +<h2 id="TaskUseSWQuali">Использование квалификатора Smallest-width</h2> + +<p>Одной из проблем, с которой сталкивались разработчики приложений для устройств Android версий до 3.2, было слишком общее определение "большого" экрана. Это касалось устройств Dell Streak, первой модели Galaxy Tab и планшетных ПК с экраном размером 7 дюймов. Многие приложения требовалось по-разному отображать на разных устройствах (например, с 5- и 7-дюймовыми экранами), хотя они и относились к одной категории "больших" экранов. В Android версии 3.2 и более поздних доступен квалификатор Smallest-width.</p> + +<p>Он позволяет определять экраны с заданной минимальной шириной в dp. Например, типичный планшетный ПК с экраном 7 дюймов имеет минимальную ширину 600 dp, и если вы хотите, чтобы приложение работало на нем в двухпанельном режиме (а на меньших экранах в однопанельном), используйте два макета из предыдущего раздела, но вместо квалификатора размера <code>large</code> укажите <code>sw600dp</code>. В таком случае на экранах, минимальная ширина которых составляет 600 dp, будет использоваться двухпанельный макет.</p> + +<ul> + <li><code>res/layout/main.xml</code>, однопанельный макет (по умолчанию): + +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane.xml all} +</li> + <li><code>res/layout-sw600dp/main.xml</code>, двухпанельный макет: + +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all} +</li> +</ul> + +<p>Это означает, что на устройствах, минимальная ширина экрана которых не меньше 600 dp, будет выбран <code>layout-sw600dp/main.xml</code> (двухпанельный макет), а на экранах меньшего размера – <code>layout/main.xml</code> (однопанельный макет).</p> + +<p>Следует учесть, что на Android-устройствах до версии 3.2 квалификатор <code>sw600dp</code> не будет работать, поэтому для них по-прежнему нужно использовать <code>large</code>. Таким образом, вам потребуется еще один файл с названием <code>res/layout-large/main.xml</code>, идентичный файлу <code>res/layout-sw600dp/main.xml</code>. В следующем разделе вы познакомитесь с методом, который позволяет избежать дублирования таких файлов макета.</p> + + +<h2 id="TaskUseAliasFilters">Использование псевдонимов макетов</h2> + +<p>Квалификатор Smallest-width работает только на устройствах Android 3.2 или более поздних версий. Для совместимости с более ранними устройствами по-прежнему следует использовать абстрактные размеры (small, normal, large и xlarge). Например, чтобы интерфейс открывался в однопанельном режиме на телефонах и в многопанельном на планшетных ПК с 7-дюймовым экраном, телевизорах и других крупных устройствах, подготовьте следующие файлы:</p> + +<p><ul> +<li><code>res/layout/main.xml:</code> однопанельный макет;</li> +<li><code>res/layout-large:</code> многопанельный макет;</li> +<li><code>res/layout-sw600dp:</code> многопанельный макет.</li> +</ul></p> + +<p>Последние два файла идентичны: один из них предназначен для устройств Android 3.2 и новее, а второй для более старых планшетных ПК и телевизоров на платформе Android.</p> + +<p>Чтобы не создавать дубликаты файлов и упростить процесс поддержки приложения, используйте псевдонимы. Например, можно определить следующие макеты:</p> + +<ul> +<li><code>res/layout/main.xml</code> (однопанельный макет);</li> +<li><code>res/layout/main_twopanes.xml</code> (двухпанельный макет).</li> +</ul> + +<p>Затем добавьте следующие два файла:</p> + +<p><ul> +<li><code>res/values-large/layout.xml</code>: +<pre> +<resources> + <item name="main" type="layout">@layout/main_twopanes</item> +</resources> +</pre> +</li> + +<li><code>res/values-sw600dp/layout.xml</code>: +<pre> +<resources> + <item name="main" type="layout">@layout/main_twopanes</item> +</resources> +</pre> + +</li> +</ul></p> + +<p>Содержание последних двух файлов одинаково, но сами по себе они не определяют макет. Они служат для того, чтобы назначить файл <PH>{@code main}</PH> в качестве псевдонима <PH>{@code main_twopanes}</PH>. Так как в них используются селекторы <code>large</code> и <code>sw600dp</code>, они применяются к планшетным ПК и телевизорам на платформе Android независимо от версии (для версий до 3.2 используется +<PH>{@code large}</PH>, а для более новых – <code>sw600dp</code>).</p> + + +<h2 id="TaskUseOriQuali">Использование квалификаторов ориентации</h2> + +<p>Хотя некоторые макеты одинаково хорошо смотрятся в вертикальной и горизонтальной ориентациях, в большинстве случаев интерфейс все же приходится адаптировать. Ниже показано, как изменяется макет в приложении News Reader в зависимости от размера и ориентации экрана.</p> + +<p><ul> +<li><b>Маленький экран, вертикальная ориентация</b>: однопанельный вид с логотипом.</li> +<li><b>Маленький экран, горизонтальная ориентация</b>: однопанельный вид с логотипом.</li> +<li><b>Планшетный ПК с 7-дюймовым экраном, вертикальная ориентация</b>: однопанельный вид с панелью действий.</li> +<li><b>Планшетный ПК с 7-дюймовым экраном, горизонтальная ориентация</b>: двухпанельный вид с панелью действий.</li> +<li><b>Планшетный ПК с 10-дюймовым экраном, вертикальная ориентация</b>: двухпанельный вид (узкий вариант) с панелью действий.</li> +<li><b>Планшетный ПК с 10-дюймовым экраном, горизонтальная ориентация</b>: двухпанельный вид (широкий вариант) с панелью действий.</li> +<li><b>Телевизор, горизонтальная ориентация</b>: двухпанельный вид с панелью действий.</li> +</ul></p> + +<p>Каждый из этих макетов определен в XML-файле в каталоге <code>res/layout/</code>. Чтобы сопоставить их с определенными конфигурациями экрана, в приложении используются псевдонимы:</p> + +<p><code>res/layout/onepane.xml:</code></p> +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane.xml all} + +<p><code>res/layout/onepane_with_bar.xml:</code></p> +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane_with_bar.xml all} + +<p><code>res/layout/twopanes.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all} + +<p><code>res/layout/twopanes_narrow.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes_narrow.xml all} + +<p>После того как все возможные макеты определены, остается сопоставить каждый из них с подходящей конфигурацией, используя квалификаторы конфигураций. Воспользуемся псевдонимами макетов:</p> + +<p><code>res/values/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values/layouts.xml all} + +<p><code>res/values-sw600dp-land/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values-sw600dp-land/layouts.xml +all} + +<p><code>res/values-sw600dp-port/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values-sw600dp-port/layouts.xml +all} + +<p><code>res/values-large-land/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values-large-land/layouts.xml all} + +<p><code>res/values-large-port/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values-large-port/layouts.xml all} + + + +<h2 id="TaskUse9Patch">Использование растровых изображений nine-patch</h2> + +<p>Чтобы интерфейс был совместим с экранами разных размеров, используемые в нем графические элементы также должны быть адаптированы соответствующим образом. Например, фон кнопки должен одинаково хорошо выглядеть независимо от ее формы.</p> + +<p>Если использовать для компонентов, размеры которых меняются, обычные изображения, то они будут равномерно сжиматься и растягиваться, и результат будет далек от идеального. Решением являются растровые изображения формата nine-patch – специальные PNG-файлы, содержащие информацию о том, какие области можно растягивать, а какие нет.</p> + +<p>Создавая растровые изображения для масштабируемых компонентов, обязательно используйте формат nine-patch. На рис. 4 показано обычное растровое изображение (увеличенное в 4 раза для наглядности), которое мы переведем в формат nine-patch.</p> + +<img src="{@docRoot}images/training/button.png" /> +<p class="img-caption"><strong>Рисунок 4</strong>. <code>button.png</code></p> + +<p>Откройте его с помощью утилиты <ode +href="{@docRoot}tools/help/draw9patch.html"><code>draw9patch</code></a>, входящей в комплект разработчика (в каталоге <code>tools/</code>). Установите метки на левом и верхнем краях, чтобы ограничить области, которые можно растягивать. Можно также провести линию вдоль правого и нижнего краев, как показано на рис. 5, чтобы отметить области, в которых содержание должно быть зафиксировано.</p> + +<img src="{@docRoot}images/training/button_with_marks.png" /> +<p class="img-caption"><strong>Рисунок 5</strong>. <code>button.9.png</code></p> + +<p>Обратите внимание на черные пиксели по краям. Метки у верхней и левой границ обозначают те области, которые можно растягивать, а метки у правой и нижней границ – те, куда должно быть помещено содержание.</p> + +<p>Также обратите внимание на расширение <code>.9.png</code>. Оно должно быть задано именно в таком виде, чтобы система могла определить, что это формат nine-patch, а не обычный PNG-файл.</p> + +<p>При применении этого фона к компоненту (с помощью <code>android:background="@drawable/button"</code>) изображение будет растянуто по размеру кнопки, как показано на рис. 6.</p> + +<img src="{@docRoot}images/training/buttons_stretched.png" /> +<p class="img-caption"><strong>Рисунок 6</strong>. Кнопки разных размеров с файлом фона <code>button.9.png</code> в формате nine-patch.</p> + |