summaryrefslogtreecommitdiffstats
path: root/docs/html-intl/ru/training/multiscreen/adaptui.jd
blob: 490a64ad2de6abf81692ac542336b4b72379903f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
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>Так как в реализации макетов существуют отличия, первое, что необходимо сделать,&nbsp;– определить, какой макет отображается в данный момент. Например, работает ли приложение в однопанельном или двухпанельном режиме. Для этого создадим запрос о том, существует ли данное представление и отображается ли оно в настоящий момент:</p>

<pre class="prettyprint">
public class NewsReaderActivity extends FragmentActivity {
    boolean mIsDualPane;

    &#64;Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_layout);

        View articleView = findViewById(R.id.article);
        mIsDualPane = articleView != null &amp;&amp; 
                        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>
&#64;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 &lt; 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 {
    ...
    &#64;Override
    public void onItemClick(AdapterView&lt;?&gt; 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&nbsp;дюймов под управлением ОС Android 3.0 или более поздней версии при вертикальной ориентации статья в приложении News Reader открывается с помощью отдельной активности, а при горизонтальной используется двухпанельный макет.</p>

<p>Это означает, что если пользователь держит планшетный ПК вертикально и на экране запущена активность для просмотра статьи, приложение должно уметь определить, что ориентация была изменена на горизонтальную. Затем оно должно соответствующим образом отреагировать на изменение, то есть завершить эту активность и вернуться к основной активности, чтобы содержание отобразилось в двухпанельном макете:</p>

<pre>
public class ArticleActivity extends FragmentActivity {
    int mCatIndex, mArtIndex;

    &#64;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>