Нет ничего более раздражающего, чем пытаться перемещаться по плохо спроектированному пользовательскому интерфейсу в мобильном приложении. То, как ваше приложение ведет себя с точки зрения навигации по экрану, может означать разницу между счастливым пользователем и тем, кто разжигает вас в Android Market. Сегодня мы фокусируемся на фокусе, а именно: на фокусе управления и на том, как его настроить в ваших пользовательских интерфейсах.
Способы ввода в Android-устройства становятся довольно разнообразными: направляющие, трекболы, сенсорные экраны, клавиатуры и многое другое. Некоторые устройства, такие как планшеты, в первую очередь ориентированы на прикосновение. Другие, такие как Google TV, не имеют сенсорного экрана и используют устройства ввода, такие как устройства с направленной панелью (d-pad).
Разработчики Android должны понимать, как пользователи перемещаются по элементам управления на экране, как и в каком порядке эти элементы управления экранами усиливаются и теряют фокус, а также как настраивать порядок фокусировки элементов управления для своих приложений, чтобы пользователи не испытывали разочарования.
Понимание Порядка Фокуса Управления
Платформа Android делает все возможное, чтобы определить соответствующий порядок управления для данного типа макета. Во многих случаях порядок фокусировки по умолчанию имеет смысл. Тем не менее, это не всегда так. Какой элемент управления должен получить фокус следующий, определяется путем нахождения ближайшего соседа текущего элемента управления в заданном направлении (вверх / вниз / влево / вправо). Когда есть несколько элементов управления, которые соответствуют этому описанию, платформа сканирует слева направо, сверху вниз, почти так же, как можно было бы прочитать книгу на английском языке.
Это имеет некоторые последствия. По умолчанию верхнему элементу управления на экране будет нечего сосредоточиться, если пользователь нажмет «Вверх», и ничего не произойдет, если пользователь нажмет «Вниз» из нижнего элемента управления на экране. Точно так же ничего не произойдет, если пользователь попытается переместиться «влево» из крайнего левого элемента управления или «вправо» из крайнего правого элемента управления. По умолчанию «обтекание» фокуса отсутствует.
Теперь давайте рассмотрим пример того, как вы можете изменить стандартное поведение фокуса на экране и заставить его работать для вас и ваших пользователей. Например, допустим, вы хотите, чтобы ваш порядок фокусировки циклически оборачивался вокруг набора элементов управления, составляющих циферблат часов.
Шаг 0: Начало работы
Мы предоставляем полный исходный код для примера приложения, обсуждаемого в этом руководстве. Вы можете скачать образец исходного кода, который мы предоставляем для ознакомления здесь.
Шаг 1. Определите макет с помощью элементов управления
Сначала создайте или отредактируйте файл ресурсов макета, используемый вашим классом Activity, например /res/layout/main.xml. Например, следующий макет определяет своего рода «циферблат» элементов управления Button с использованием RelativeLayout.
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
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 
 | 
 <?xml version=»1.0″ encoding=»utf-8″?> 
<RelativeLayout 
    xmlns:android=»http://schemas.android.com/apk/res/android» 
    android:layout_width=»fill_parent» 
    android:layout_height=»fill_parent»> 
    <Button 
        style=»@style/clockFaceNum» 
        android:text=»12″ 
        android:id=»@+id/button12″ 
        android:layout_alignParentTop=»true» 
        android:layout_centerHorizontal=»true»> 
    </Button> 
    <Button 
        style=»@style/clockFaceNum» 
        android:text=»11″ 
        android:id=»@+id/button11″ 
        android:layout_below=»@+id/button12″ 
        android:layout_toLeftOf=»@+id/button12″> 
    </Button> 
    <Button 
        style=»@style/clockFaceNum» 
        android:text=»1″ 
        android:id=»@+id/button1″ 
        android:layout_below=»@+id/button12″ 
        android:layout_toRightOf=»@+id/button12″> 
    </Button> 
    <Button 
        style=»@style/clockFaceNum» 
        android:text=»10″ 
        android:id=»@+id/button10″ 
        android:layout_below=»@+id/button11″ 
        android:layout_toLeftOf=»@+id/button11″> 
    </Button> 
    <Button 
        style=»@style/clockFaceNum» 
        android:text=»2″ 
        android:id=»@+id/button2″ 
        android:layout_below=»@+id/button1″ 
        android:layout_toRightOf=»@+id/button1″> 
    </Button> 
    <Button 
        style=»@style/clockFaceNum» 
        android:text=»9″ 
        android:id=»@+id/button9″ 
        android:layout_below=»@+id/button10″ 
        android:layout_toLeftOf=»@+id/button10″> 
    </Button> 
    <Button 
        style=»@style/clockFaceNum» 
        android:text=»3″ 
        android:id=»@+id/button3″ 
        android:layout_below=»@+id/button2″ 
        android:layout_toRightOf=»@+id/button2″> 
    </Button> 
    <Button 
        style=»@style/clockFaceNum» 
        android:text=»8″ 
        android:id=»@+id/button8″ 
        android:layout_below=»@+id/button9″ 
        android:layout_toRightOf=»@+id/button9″> 
    </Button> 
    <Button 
        style=»@style/clockFaceNum» 
        android:text=»4″ 
        android:id=»@+id/button4″ 
        android:layout_below=»@+id/button3″ 
        android:layout_toLeftOf=»@+id/button3″> 
    </Button> 
    <Button 
        style=»@style/clockFaceNum» 
        android:text=»7″ 
        android:id=»@+id/button7″ 
        android:layout_below=»@+id/button8″ 
        android:layout_toRightOf=»@+id/button8″> 
    </Button> 
    <Button 
        style=»@style/clockFaceNum» 
        android:text=»5″ 
        android:id=»@+id/button5″ 
        android:layout_below=»@+id/button4″ 
        android:layout_toLeftOf=»@+id/button4″> 
    </Button> 
    <Button 
        style=»@style/clockFaceNum» 
        android:text=»6″ 
        android:id=»@+id/button6″ 
        android:layout_below=»@+id/button5″ 
        android:layout_centerHorizontal=»true»> 
    </Button> 
</RelativeLayout> 
 | 
Стиль с именем clockFaceNum определен в файле /res/values/styles.xml следующим образом:
<? xml version = "1.0" encoding = "utf-8"?> <ресурсы> <стиль имя = "clockFaceNum"> <пункт имя = "андроид: layout_width"> 38dp </ элемент> <пункт имя = "Android: layout_height"> 38dp </ пункт> <пункт имя = "андроид: OnClick"> numClicked </ элемент> <пункт имя = "андроид: TextSize"> 9sp </ элемент> </ Стиль> </ Ресурсы>
Получившийся экран выглядит так:

Шаг 2. Просмотр порядка фокусировки по умолчанию
Давайте рассмотрим порядок фокусировки по умолчанию для элементов управления Button на циферблате в этом RelativeLayout. Если пользователь сфокусирован на кнопке 12 и нажимает «вниз» на клавиатуре направления, следующим элементом управления для фокусировки будет кнопка 11, затем кнопка 10 и т. Д.
Путь «вниз» по умолчанию показан здесь:

Шаг 3. Предоставление пользовательского элемента управления порядком фокусировки
Допустим, мы хотим, чтобы пользователь мог перемещаться по элементам управления циферблатом только по часовой стрелке или против часовой стрелки, а не по умолчанию, как показано:

Мы можем определить это поведение, указав для каждой кнопки, какой элемент управления должен получить следующий фокус. Существует четыре атрибута XML, которые вы можете установить в любом элементе управления View для определения порядка фокусировки. Эти атрибуты:
- android: nextFocusUp-Этот атрибут определяет элемент управления, который должен получить фокус, если пользователь перемещается вверх
 - android: nextFocusDown-Этот атрибут определяет элемент управления, который должен получить фокус, если пользователь перемещается вниз
 - android: nextFocusLeft-Этот атрибут определяет элемент управления, который должен получить фокус, если пользователь перемещается влево
 - android: nextFocusRight-Этот атрибут определяет элемент управления, который должен получить фокус, если пользователь перемещается вправо
 
Допустим, мы хотим, чтобы вся навигация «Вниз» и «Вправо» позволяла пользователю перемещаться по часовой стрелке, а элементы управления «Кнопка» — по часовой стрелке, а вся навигация «Вверх» и «Влево» позволяла пользователю перемещаться по элементам управления в противоположную сторону. по часовой стрелке Затем мы должны были бы определить эти четыре атрибута для каждого элемента управления. Например, если вы переместили «Вниз» или «Вправо» из 12 кнопок, вы бы достигли 1 кнопки. Точно так же, если вы переместились «вверх» или «влево» от кнопки 12, вы бы достигли кнопки 11.
Полное определение этого нового расположения циферблата выглядит следующим образом:
| 
 001 
002 
003 
004 
005 
006 
007 
008 
009 
010 
011 
012 
013 
014 
015 
016 
017 
018 
019 
020 
021 
022 
023 
024 
025 
026 
027 
028 
029 
030 
031 
032 
033 
034 
035 
036 
037 
038 
039 
040 
041 
042 
043 
044 
045 
046 
047 
048 
049 
050 
051 
052 
053 
054 
055 
056 
057 
058 
059 
060 
061 
062 
063 
064 
065 
066 
067 
068 
069 
070 
071 
072 
073 
074 
075 
076 
077 
078 
079 
080 
081 
082 
083 
084 
085 
086 
087 
088 
089 
090 
091 
092 
093 
094 
095 
096 
097 
098 
099 
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 
 | 
 <?xml version=»1.0″ encoding=»utf-8″?> 
<RelativeLayout 
    xmlns:android=»http://schemas.android.com/apk/res/android» 
    android:layout_width=»fill_parent» 
    android:layout_height=»fill_parent»> 
    <Button 
        style=»@style/clockFaceNum» 
        android:text=»12″ 
        android:id=»@+id/button12″ 
        android:layout_alignParentTop=»true» 
        android:layout_centerHorizontal=»true» 
        android:nextFocusUp=»@+id/button11″ 
        android:nextFocusLeft=»@+id/button11″ 
        android:nextFocusRight=»@+id/button1″ 
        android:nextFocusDown=»@+id/button1″> 
    </Button> 
    <Button 
        style=»@style/clockFaceNum» 
        android:text=»11″ 
        android:id=»@+id/button11″ 
        android:layout_below=»@+id/button12″ 
        android:layout_toLeftOf=»@+id/button12″ 
        android:nextFocusUp=»@+id/button10″ 
        android:nextFocusLeft=»@+id/button10″ 
        android:nextFocusRight=»@+id/button12″ 
        android:nextFocusDown=»@+id/button12″> 
    </Button> 
    <Button 
        style=»@style/clockFaceNum» 
        android:text=»1″ 
        android:id=»@+id/button1″ 
        android:layout_below=»@+id/button12″ 
        android:layout_toRightOf=»@+id/button12″ 
        android:nextFocusUp=»@+id/button12″ 
        android:nextFocusLeft=»@+id/button12″ 
        android:nextFocusRight=»@+id/button2″ 
        android:nextFocusDown=»@+id/button2″> 
    </Button> 
    <Button 
        style=»@style/clockFaceNum» 
        android:text=»10″ 
        android:id=»@+id/button10″ 
        android:layout_below=»@+id/button11″ 
        android:layout_toLeftOf=»@+id/button11″ 
        android:nextFocusUp=»@+id/button9″ 
        android:nextFocusLeft=»@+id/button9″ 
        android:nextFocusRight=»@+id/button11″ 
        android:nextFocusDown=»@+id/button11″> 
    </Button> 
    <Button 
        style=»@style/clockFaceNum» 
        android:text=»2″ 
        android:id=»@+id/button2″ 
        android:layout_below=»@+id/button1″ 
        android:layout_toRightOf=»@+id/button1″ 
        android:nextFocusUp=»@+id/button1″ 
        android:nextFocusLeft=»@+id/button1″ 
        android:nextFocusRight=»@+id/button3″ 
        android:nextFocusDown=»@+id/button3″> 
    </Button> 
    <Button 
        style=»@style/clockFaceNum» 
        android:text=»9″ 
        android:id=»@+id/button9″ 
        android:layout_below=»@+id/button10″ 
        android:layout_toLeftOf=»@+id/button10″ 
        android:nextFocusUp=»@+id/button8″ 
        android:nextFocusLeft=»@+id/button8″ 
        android:nextFocusRight=»@+id/button10″ 
        android:nextFocusDown=»@+id/button10″> 
    </Button> 
    <Button 
        style=»@style/clockFaceNum» 
        android:text=»3″ 
        android:id=»@+id/button3″ 
        android:layout_below=»@+id/button2″ 
        android:layout_toRightOf=»@+id/button2″ 
        android:nextFocusUp=»@+id/button2″ 
        android:nextFocusLeft=»@+id/button2″ 
        android:nextFocusRight=»@+id/button4″ 
        android:nextFocusDown=»@+id/button4″> 
    </Button> 
    <Button 
        style=»@style/clockFaceNum» 
        android:text=»8″ 
        android:id=»@+id/button8″ 
        android:layout_below=»@+id/button9″ 
        android:layout_toRightOf=»@+id/button9″ 
        android:nextFocusUp=»@+id/button7″ 
        android:nextFocusLeft=»@+id/button7″ 
        android:nextFocusRight=»@+id/button9″ 
        android:nextFocusDown=»@+id/button9″> 
    </Button> 
    <Button 
        style=»@style/clockFaceNum» 
        android:text=»4″ 
        android:id=»@+id/button4″ 
        android:layout_below=»@+id/button3″ 
        android:layout_toLeftOf=»@+id/button3″ 
        android:nextFocusUp=»@+id/button3″ 
        android:nextFocusLeft=»@+id/button3″ 
        android:nextFocusRight=»@+id/button5″ 
        android:nextFocusDown=»@+id/button5″> 
    </Button> 
    <Button 
        style=»@style/clockFaceNum» 
        android:text=»7″ 
        android:id=»@+id/button7″ 
        android:layout_below=»@+id/button8″ 
        android:layout_toRightOf=»@+id/button8″ 
        android:nextFocusUp=»@+id/button6″ 
        android:nextFocusLeft=»@+id/button6″ 
        android:nextFocusRight=»@+id/button8″ 
        android:nextFocusDown=»@+id/button8″> 
    </Button> 
    <Button 
        style=»@style/clockFaceNum» 
        android:text=»5″ 
        android:id=»@+id/button5″ 
        android:layout_below=»@+id/button4″ 
        android:layout_toLeftOf=»@+id/button4″ 
        android:nextFocusUp=»@+id/button4″ 
        android:nextFocusLeft=»@+id/button4″ 
        android:nextFocusRight=»@+id/button6″ 
        android:nextFocusDown=»@+id/button6″> 
    </Button> 
    <Button 
        style=»@style/clockFaceNum» 
        android:text=»6″ 
        android:id=»@+id/button6″ 
        android:layout_below=»@+id/button5″ 
        android:layout_centerHorizontal=»true» 
        android:nextFocusUp=»@+id/button5″ 
        android:nextFocusLeft=»@+id/button5″ 
        android:nextFocusRight=»@+id/button7″ 
        android:nextFocusDown=»@+id/button7″> 
    </Button> 
</RelativeLayout> 
 | 
Поэтому наш новый путь «вниз», начинающийся с 12-й кнопки, теперь выглядит следующим образом:

Шаг 4: Установка начального контрольного фокуса
Наконец, вот трюк для установки элемента управления по умолчанию, чтобы получить фокус на заданном экране из вашего файла макета. Вы можете сделать это только для одного элемента управления View в каждом файле.
Используйте тег в элементе управления View, чтобы установить начальный фокус на экране. Например, мы могли бы хотеть обновить 12 Кнопок, чтобы получить начальный фокус, как это:
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
 | 
 <Button 
    style=»@style/clockFaceNum» 
    android:text=»12″ 
    android:id=»@+id/button12″ 
    android:layout_alignParentTop=»true» 
    android:layout_centerHorizontal=»true» 
    android:nextFocusUp=»@+id/button11″ 
    android:nextFocusLeft=»@+id/button11″ 
    android:nextFocusRight=»@+id/button1″ 
    android:nextFocusDown=»@+id/button1″> 
    <requestFocus /> 
</Button> 
 | 
Конечно, вы также можете использовать программный метод для установки фокуса управления, используя метод класса View, называемый requestFocus ().
Вывод
Разработчики Android должны помнить, что разные пользователи будут перемещаться по пользовательскому интерфейсу приложения, используя разные методы ввода. Некоторые методы позволяют легко переключаться между элементами управления экрана, в то время как другие могут усложнять навигацию. Разработчики могут предоставить индивидуальные заказы на фокусировку, которые могут значительно улучшить взаимодействие пользователя с приложением. Пожалуйста, не забывайте о пользователях клавиатуры. ☺
Об авторах
Разработчики мобильных приложений Лорен Дарси и Шейн Кондер являются соавторами нескольких книг по разработке Android: углубленная книга по программированию под названием « Разработка беспроводных приложений для Android, второе издание» и « Самс научи себя разработке приложений для Android за 24 часа, второе издание» . Когда они не пишут, они тратят свое время на разработку мобильного программного обеспечения в своей компании и оказание консультационных услуг. С ними можно связаться по электронной почте androidwirelessdev+mt@gmail.com , через их блог на androidbook.blogspot.com и в Twitter @androidwireless .


