Статьи

Лучшие пользовательские интерфейсы с панелью действий Android

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

Панель действий была введена в Android 3.0, хотя поддержка более старых версий может быть достигнута с помощью библиотеки поддержки Android . Перед выпуском меню параметров обычно использовалось для предоставления действий и функций, которые теперь отображаются на панели действий. Панель действий по умолчанию включена во все действия для приложений с minSdkVersion

В этом руководстве рассматривается настройка панели действий и рассматриваются различные конфигурации, которые она предлагает.

Настройка панели действий

Для начала мы собираемся создать новый проект. Мы не будем использовать библиотеку поддержки Android, поэтому убедитесь, что вы выбрали минимальную версию SDK 11 или выше. Когда вы запустите свой проект, панель действий будет включена в верхней части экрана вашего приложения. Он включен во все действия, которые используют или наследуют от темы Theme.Holo, которая используется по умолчанию, если для minSdkVersion Типичная панель действий показана на следующем рисунке.

Панель действий

Панель действий состоит из:

  • Значок приложения — используется для обозначения вашего приложения логотипом или значком.
  • Управление представлением — это также может быть использовано для определения приложения или конкретной активности пользователя по заголовку. Если ваше приложение имеет разные представления, его также можно использовать для их отображения и обеспечения легкого переключения между представлениями.
  • Кнопки действий — они используются для отображения наиболее важных и / или часто используемых действий. Если недостаточно места для отображения всех кнопок действий, те, которые не помещаются, автоматически перемещаются в переполнение действий.
  • Переполнение действия — это используется для менее используемых действий.

Добавление действий на панель действий

Чтобы добавить действия на панель действий, создайте файл XML в каталоге res/menu Можно определить действия в коде Java, но вы будете писать меньше кода, если будете использовать XML. Содержимое res/menu/main_activity_bar.xml В этом примере мы используем пакет значков панели действий для значков действий. Загрузите его и скопируйте необходимые значки в каталог res/drawable-xxxx

 <menu xmlns:android="http://schemas.android.com/apk/res/android" >
  <item android:id="@+id/action_search"
    android:icon="@drawable/ic_action_search"
    android:title="@string/action_search"
    android:showAsAction="ifRoom" />
  <item android:id="@+id/action_record"
    android:icon="@drawable/ic_action_video"
    android:title="@string/action_record"
    android:showAsAction="ifRoom" />
  <item android:id="@+id/action_save"
    android:icon="@drawable/ic_action_save"
    android:title="@string/action_save"
    android:showAsAction="ifRoom" />
  <item android:id="@+id/action_label"
    android:icon="@drawable/ic_action_new_label"
    android:title="@string/action_label"
    android:showAsAction="ifRoom" />
  <item android:id="@+id/action_play"
    android:icon="@drawable/ic_action_play"
    android:title="@string/action_play"
    android:showAsAction="ifRoom" />
  <item android:id="@+id/action_settings"
    android:title="@string/action_settings"
    android:showAsAction="never" />
</menu>

Затем добавьте строковые литералы в res/values/strings.xml

 <?xml version="1.0" encoding="utf-8"?>
<resources>
  <string name="app_name">ActionBar</string>
  <string name="action_settings">Settings</string>
  <string name="action_search">Search</string>
  <string name="action_record">Record Video</string>
  <string name="action_save">Save</string>
  <string name="action_label">Add Label</string>
  <string name="action_play">Play Video</string>
  <string name="hello_world">Hello world!</string>
</resources>

Атрибут icontitle Чтобы отобразить titlewithTextshowAsAction Например, вы можете использовать android:showAsAction="ifRoom|withText" Чтобы действие всегда отображалось, используйте alwaysshowAsAction Тем не менее, это не рекомендуется, так как это может вызвать нежелательные эффекты макета на небольших экранах. Если необходимо, ограничьте его одним или двумя пунктами.

Вы всегда должны определять атрибут title

  • Заголовок будет использоваться в переполнении, если на панели действий недостаточно места для элемента действия.
  • Для пользователя может быть неочевидным, что делает элемент действия только из-за его значка, поэтому предоставление заголовка позволяет ему долго нажимать на него, чтобы открыть подсказку, отображающую заголовок.
  • Заголовок обеспечивает доступ для пользователей с нарушениями зрения, так как программа чтения с экрана может прочитать заголовок пункта меню.

Далее нам нужно реализовать метод обратного вызова onCreateOptionsMenu() Это раздувает ресурс меню в заданный объект Menu Код для этой функции показан ниже.

 @Override
public boolean onCreateOptionsMenu(Menu menu) {
  MenuInflater inflater = getMenuInflater();

  inflater.inflate(R.menu.main_activity_bar, menu);
  return super.onCreateOptionsMenu(menu);
}

Запустите проект, и вы увидите нечто похожее на следующий рисунок. Некоторые кнопки действий отображаются на панели действий, а остальные можно увидеть в расширенном переполнении действий. При переходе в горизонтальный режим панель действий автоматически адаптируется к новой ширине и отображает больше действий в соответствии с рекомендациями, приведенными в файле XML.

Панель действий с кнопками действий

Разделение панели действий

Поскольку элементы действий совместно используют область действия со значком и заголовком приложения, вы можете разделить панель действий так, чтобы элементы действия отображались в нижней части экрана. Это даст им больше места, и, таким образом, больше элементов будет видно пользователю. Если места достаточно, например, на больших экранах или в альбомном режиме, панель действий не будет разделена.

Панель действий Split

Чтобы разделить панель действий, добавьте android:uiOptions="splitActionBarWhenNarrow" Это поддерживает только API уровня 14 и выше. Чтобы добавить поддержку более низких уровней, используйте следующий элемент meta-data

 <activity
  android:name="com.example.actionbar.MainActivity"
  android:label="@string/app_name"
  android:uiOptions="splitActionBarWhenNarrow" >
  <meta-data android:name="android.support.UI_OPTIONS"
    android:value="splitActionBarWhenNarrow" />
  <intent-filter>
    <action android:name="android.intent.action.MAIN" />

    <category android:name="android.intent.category.LAUNCHER" />
  </intent-filter>
</activity>

Скрытие панели действий

Возможно, вы не захотите, чтобы панель действий всегда была видна пользователю. Типичным примером этого является приложение Галерея, которое скрывает панель действий, когда пользователь смотрит на изображение, и показывает панель действий, когда они касаются изображения. Чтобы переключать видимость панели действий на ощупь, добавьте следующее в свой файл активности.

 @Override
public boolean onTouchEvent(MotionEvent event) {
  if(event.getAction() == MotionEvent.ACTION_DOWN) {
    toggleActionBar();
  }
  return true;
}

private void toggleActionBar() {
  ActionBar actionBar = getActionBar();

  if(actionBar != null) {
    if(actionBar.isShowing()) {
      actionBar.hide();
    }
    else {
      actionBar.show();
    }
  }
}

При запуске приложения вы сможете показать / скрыть панель действий, нажав на экран. Вы заметите, что содержимое на экране меняет положение с каждым показом / скрытием. Это связано с тем, что когда вы скрываете / отображаете панель действий, активность изменяется, влияя на размер и позицию контента. Чтобы предотвратить это, вы должны вместо этого наложить панель действий, как описано далее.

Наложение панели действий

Наложение панели действий обеспечивает лучший способ скрытия / показа, поскольку активность не изменяется при каждом скрытии / показе, что позволяет вашему контенту оставаться на месте. Вы можете включить наложение, установив для android:windowActionBarOverlaytrue Вы должны использовать тему Theme.Holo (или один из ее потомков). Если ваш minSdkVersion

В res/values/styles.xml

 <resources>
  <style name="AppBaseTheme" parent="android:Theme.Light">
  </style>

  <!-- Application theme. -->
  <style name="AppTheme" parent="AppBaseTheme">
    <item name="android:windowActionBarOverlay">true</item>
  </style>
</resources>

Запустите приложение и обратите внимание, что содержимое на экране не меняет своего положения, когда панель действий скрыта и открыта.

Добавление навигации вверх

Все экраны в вашем приложении, которые не являются основным входом в ваше приложение («домашний» экран), должны предлагать пользователю способ перехода к логическому родительскому экрану в иерархии приложения, нажав кнопку «Вверх» на панели действий. Начиная с уровня API 14, вы можете объявить логического родителя каждого действия, указав атрибут android:parentActivityName Для поддержки более низких версий activityandroid.support.PARENT_ACTIVITYandroid:parentActivityName

Мы добавим еще одно действие, чтобы продемонстрировать это. Добавьте другой файл активности с именем SecondActivity Мы вызываем setDisplayHomeAsUpEnabled() Это добавит левую каретку рядом со значком приложения. Когда она нажата, действие получает вызов onOptionsItemSelected()

 package com.example.actionbar;

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.NavUtils;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;

public class SecondActivity extends Activity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.second_activity);
    getActionBar().setDisplayHomeAsUpEnabled(true);
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu items for use in the action bar
    MenuInflater inflater = getMenuInflater();

    inflater.inflate(R.menu.second_activity_bar, menu);
    return super.onCreateOptionsMenu(menu);
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
      // Respond to the action bar's Up/Home button
      case android.R.id.home:
        NavUtils.navigateUpFromSameTask(this);
        return true;
    }

    return super.onOptionsItemSelected(item);
  }
}

В res/layout/second_activity.xml

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/RelativeLayout1"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="vertical" >

  <TextView
    android:id="@+id/TextView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:layout_centerVertical="true"
    android:text="@string/hello_world_again" />
</RelativeLayout>

Затем добавьте следующие строки в res/values.strings.xml

 <string name="hello_world_again">Hello world, again!</string>
<string name="second">Go To Second Activity</string>
<string name="second_activity_title">Second Activity</string>

Затем создайте файл ресурсов для панели действий второго действия. Назовите этот файл res/menu/second_activity_bar.xml

 <menu xmlns:android="http://schemas.android.com/apk/res/android" >
  <item
    android:id="@+id/action_settings"
    android:orderInCategory="100"
    android:showAsAction="never"
    android:title="@string/action_settings"/>
</menu>

Затем добавьте действие в файл манифеста:

 <application>
  ...
  <activity
    android:name="com.example.actionbar.SecondActivity"
    android:label="@string/second_activity_title"
    android:parentActivityName="com.example.actionbar.MainActivity" >
    <meta-data
      android:name="android.support.PARENT_ACTIVITY"
      android:value="com.example.actionbar.MainActivity" />
  </activity>
  ...
</application>

Затем добавьте кнопку в основное действие в res/layout/activity_main.xml

 <Button
  android:id="@+id/second"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:layout_alignLeft="@+id/TextView1"
  android:layout_centerVertical="true"
  android:onClick="openSecondActivity"
  android:text="@string/second" />

Также добавьте обработчик onClickMainActivity.java Эта функция, показанная ниже, запускает второе действие при нажатии кнопки.

 public void openSecondActivity(View view) {
  Intent intent = new Intent(this, SecondActivity.class);
  startActivity(intent);
}

Запустите приложение. На первом экране будет кнопка, которая при нажатии откроет второй экран с панелью действий, показанной ниже. Обратите внимание на каретку, которая перемещается к родительской активности при нажатии.

Навигация вверх

Интерактивность Action Bar

Пока что мы создали элементы действий, которые ничего не делают при нажатии. Далее мы увидим, как добавить интерактивность на панель действий.

Обработка щелчков на элементах действий

При нажатии действия вызывается метод действия onOptionsItemSelected() Действие можно определить, вызвав getItemId() Добавьте метод onOptionsItemSelected()MainActivity.java Здесь мы показываем другое сообщение, когда на каждое действие нажимают.

 @Override
public boolean onOptionsItemSelected(MenuItem item) {
  // Handle presses on the action bar items
  switch (item.getItemId()) {
    case R.id.action_search:
      // Code you want run when activity is clicked
      Toast.makeText(this, "Search clicked", Toast.LENGTH_SHORT).show();
      return true;
    case R.id.action_record:
      Toast.makeText(this, "Record clicked", Toast.LENGTH_SHORT).show();
      return true;
    case R.id.action_save:
      Toast.makeText(this, "Save clicked", Toast.LENGTH_SHORT).show();
      return true;
    case R.id.action_label:
      Toast.makeText(this, "Label clicked", Toast.LENGTH_SHORT).show();
      return true;
    case R.id.action_play:
      Toast.makeText(this, "Play clicked", Toast.LENGTH_SHORT).show();
      return true;
    case R.id.action_settings:
      Toast.makeText(this, "Settings clicked", Toast.LENGTH_SHORT).show();
      return true;
    default:
      return super.onOptionsItemSelected(item);
  }
}

Виды действий

Представления действий — это интерактивные виджеты, которые отображаются на панели действий вместо кнопок действий. Они позволяют размещать случайно используемые элементы пользовательского интерфейса на панели действий, что позволяет избежать ненужного использования места на экране и переключения действий для их использования.

Чтобы объявить представление действия, используйте actionLayoutactionViewClass В качестве быстрого примера, чтобы добавить виджет SearchViewres/menu/main_activity_bar.xml

 <item android:id="@+id/action_search"
  android:icon="@drawable/ic_action_search"
  android:title="@string/action_search"
  android:showAsAction="ifRoom|collapseActionView"
  android:actionViewClass="android.widget.SearchView" />

При запуске приложения появится окно редактирования текста при нажатии на действие поиска.

Поиск виджета

Мы добавим наш собственный вид на панель действий. Создайте файл макета с именем res/layout/my_action.xml Это будет ресурс макета пользовательского представления.

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent" >
  <TextView
    android:id="@+id/myActionTextView"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_weight="1"
    android:text="Type here:"
    android:gravity="right" />
  <EditText
    android:id="@+id/myActionEditText"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_weight="1"
    android:gravity="left" />
</LinearLayout>

Затем добавьте элемент действия в файл res/menu/main_activity_bar.xml

 <item android:id="@+id/my_action"
  android:icon="@drawable/ic_action_edit"
  android:title="My Action"
  android:showAsAction="ifRoom|collapseActionView"
  android:actionLayout="@layout/my_action" />

Это будет использовать макет, который мы добавили выше. collapseActionView Нажатие на каретку вверх выходит из вида действия.

Пользовательский вид действия

Затем обновил основной файл активности MainActivity.java Обратите внимание на комментарии по всему коду.

 package com.example.actionbar;

import android.os.Bundle;
import android.app.ActionBar;
import android.app.Activity;
import android.content.Intent;
import android.support.v4.view.MenuItemCompat;
import android.support.v4.view.MenuItemCompat.OnActionExpandListener;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity implements TextView.OnEditorActionListener {

  private MenuItem myActionMenuItem;
  private EditText myActionEditText;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu items for use in the action bar
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.main_activity_bar, menu);
  
    // Here we get the action view we defined
    myActionMenuItem = menu.findItem(R.id.my_action);
    View actionView = myActionMenuItem.getActionView();
  
    // We then get the edit text view that is part of the action view
    if(actionView != null) {
      myActionEditText = (EditText) actionView.findViewById(R.id.myActionEditText);

      if(myActionEditText != null) {
        // We set a listener that will be called when the return/enter key is pressed
        myActionEditText.setOnEditorActionListener(this);
      }   
    }
  
    // For support of API level 14 and below, we use MenuItemCompat
    MenuItemCompat.setOnActionExpandListener(myActionMenuItem, new OnActionExpandListener() {
      @Override
      public boolean onMenuItemActionCollapse(MenuItem item) {
        // Do something when collapsed
        return true;  // Return true to collapse action view
      }

      @Override
      public boolean onMenuItemActionExpand(MenuItem item) {
        // Do something when expanded
        if(myActionEditText != null) {
          myActionEditText.setText("");
        }

        return true;  // Return true to expand action view
      }
    });
  
    return super.onCreateOptionsMenu(menu);
  }

  @Override
  public boolean onTouchEvent(MotionEvent event) {
    if(event.getAction() == MotionEvent.ACTION_DOWN) {
      toggleActionBar();
    }
  
    return true;
  }

  private void toggleActionBar() {
    ActionBar actionBar = getActionBar();

    if(actionBar != null) {
      if(actionBar.isShowing()) {
        actionBar.hide();
      }
      else {
        actionBar.show();
      }
    }
  }

  public void openSecondActivity(View view) {
    Intent intent = new Intent(this, SecondActivity.class);
    startActivity(intent);
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    // Handle presses on the action bar items
    switch (item.getItemId()) {
      case R.id.action_search:
        // Code you want run when activity is clicked
        Toast.makeText(this, "Search clicked", Toast.LENGTH_SHORT).show();
        return true;
      case R.id.action_record:
        Toast.makeText(this, "Record clicked", Toast.LENGTH_SHORT).show();
        return true;
      case R.id.action_save:
        Toast.makeText(this, "Save clicked", Toast.LENGTH_SHORT).show();
        return true;
      case R.id.action_label:
        Toast.makeText(this, "Label clicked", Toast.LENGTH_SHORT).show();
        return true;
      case R.id.action_play:
        Toast.makeText(this, "Play clicked", Toast.LENGTH_SHORT).show();
        return true;
      case R.id.action_settings:
        Toast.makeText(this, "Settings clicked", Toast.LENGTH_SHORT).show();
        return true;
      default:
        return super.onOptionsItemSelected(item);
    }
  }

  @Override
  public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) {
    if(keyEvent != null) {
      // When the return key is pressed, we get the text the user entered, display it and collapse the view
      if(keyEvent.getAction() == KeyEvent.ACTION_DOWN && keyEvent.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
        CharSequence textInput = textView.getText();
        // Do something useful with the text
        Toast.makeText(this, textInput, Toast.LENGTH_SHORT).show();
        MenuItemCompat.collapseActionView(myActionMenuItem);
      }
    }
    return false;
  }
}

В этом коде мы получаем представление редактирования текста в макете представления действия myActionEditText Мы хотим, чтобы операция выполнялась, когда пользователь вводит какой-то текст и нажимает клавишу возврата. По умолчанию, когда пользователь нажимает Return, курсор переходит на новую строку. Вместо этого мы хотим свернуть вид действия и получить ввод пользователя. Это делается методом onEditorAction Если это Enter, ввод текста захватывается и отображается. Затем вид действия свернут.

Мы устанавливаем слушателя в представлении действия с помощью MenuItemCompat.setOnActionExpandListener MenuItemCompat

По умолчанию, когда пользователь вводит текст и покидает вид действия, при его повторном расширении предыдущий текст все еще виден. Мы используем onMenuItemActionExpand()

Вывод

Панель действий является важным элементом дизайна, и ее можно использовать для значительного улучшения пользовательского интерфейса приложения. Мы рассмотрели некоторые конфигурации, которые вы можете использовать на панели действий для пользовательского интерфейса вашего приложения, но есть и другие. Для получения дополнительной информации ознакомьтесь с документацией . Вы можете увидеть код, используемый в этой статье на GitHub.