sobota, 25 października 2014

Pojedynek z Androidem - odc. 16 ActionBar (uzupełnienia)

Tym razem kilka uzupełnień związanych z ActionBar. Moje uwagi:

  • podobać się może kompatybilność wstecz i możliwość używania nawet na dość starych urządzeniach.
  • ukrywanie i zarządzenie widokiem trochę toporne jak dla mnie, ale da się przeżyć
  • nawigacje zakładkowa i listowa - przyzwoite, ale nic nadzwyczajnego nie widzę, w Windows możemy wstawić dowolną zawartość do paska aplikacyjnego, a poza tym mamy nowoczesne kontrolki Hub i Pivot do nawigacji
  • interaktywne widoki akcji na pasku - własne lub predefiniowane kontrolki pokazywane na stałe lub rozwijane, spełnia to swoją rolę. W Windows 8.x oraz Windows Phone 8.1 (XAML WinRT, HTML5) każdy może ogólnodostępnymi metodami dla kontrolek modyfikować zawartość paska aplikacyjnego (jest to normalna kontrolka). W Windows Phone nie nowszym niż 8.0 i w Silverlight na WP 8.1 mamy komponent systemowy o dość ograniczonej konfiguracji, który nie jest kontrolką XAML. W Android nie mamy do końca uniwersalnych mechanizmów dla całej platformy w zakresie modyfikacji zawartości komponentów wizualnych mimo wprowadzenia uniwersalnych fragmentów (może wynika to z tego, że dołożono je później do platformy, w Windows uniwersalne kontrolki były od początku)

Szczegóły poniżej:

 

Poprawa interakcji dzięki ActionBar

Dostępny na wszystkie wersje Android

Sterowanie wyglądem

  • obrazki
    • setIcon - inna ikona niż domyślna ikona aktywności
    • setLogo - ustawienie większego obrazka niż ikona po lewej stronie
    • setBackgroundDrawable - użycie bitmapy lub czegoś podobnego do tła
  • tekst
    • setTitle
    • setSubtitle
    • setDisplayShowTitleEnabled - pokazywanie/ukrywanie tytułu i podtytułu

Ukrywanie

  • programowo
    • ActionBar.hide / ActionBar.show
    • ActionBar.isShowing - informacja, czy pasek jest widoczny
  • statycznie
    • aktywność z motywem Theme.Holo.NoActionBar

Overlaying

Lepszy user experience przy ukrywaniu/pokazywaniu

  • Overlay pozwala ukrywać/pokazywać ActionBar bez resizowania aktywności
  • Włączanie overlay przy pomocy stylu
    • zdefiniowanie nowego stylu dziedziczącego po Theme.Holo
    • ustawienie windowActionBarOverlay na true
  • Włączanie overlay programowo
    • pobieramy referencję na okno za pomocą Activity.getWindow
    • używamy requestFeature do zatwierdzenia Window.FEATURE_ACTION_BAR_OVERLAY
  • aplikacja musi określić, co ukrywa/pokazuje ActionBar
    • zwykle zdarzenia dotykowe
    • często ukrywamy po wyborze akcji

public class XActivity extends Activity  {

        …

        @Override

        public boolean onTouchEvent(MotionEvent event)  {

                if (event.getAction() == MotionEvent.ACTION_DOWN)

                        toggleActionBar();

                return true;

        }

        private void toggleActionBar()  {

                ActionBar actionBar = getActionBar();

                if (actionBar.isShowing())

                        actionBar.hide();

                else

                        actionBar.show();

        }

}

values/styles.xml

<resources>

          <style name=”Theme.Holo.ActionBarOverlay” parent=”android:style/Theme.Holo”>

                   <item name=”android:windowActionBarOverlay”>true</item>

          </style>

</resources>

manifest

<activity …

                    android.theme=”style/Theme.Holo.ActionBarOverlay”

                    …>

            …

</activity>

Nawigacja

Tryby nawigacji

  • standardowa
  • zakładki
  • lista - wybór widoków z listy drop-down

Kontrolowanie umieszczenia zakładek

  • W zależności od dostępnej przestrzeni
    • stos zakładek pod głównym ActionBar, jeśli zachodzi taka potrzeba
    • na głównym ActionBar, jeśli pozwala przestrzeń
    • możliwość robienia miejsca przez umieszczenie listy akcji na dole i ukrywanie ikony/tytułu

Pokazywanie na ActionBar:

ActionBar actionBar = getActionBar();

 

int currentOptions = actionBar.getDisplayOptions();

boolean currentVisibleValue = (currentOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0;

boolean newVisibleValue = !currentVisibleValue;

 

actionBar.setDisplayShowHomeEnabled(newVisibleValue);

actionBar.setDisplayShowTitleEnabled(newVisibleValue);

Nawigacja listowa

  • lista jest tworzona jako SpinnerAdapter
    • w większości przypadków ukrywamy tytuł
  • każda pozycja reprezentuje ekran
  • każdy ekran zaimplementowany jako Fragment

ActionBar.OnNavigationListener

  • pojedyncza instancja obsługuje wszystkie ekrany
  • onNavigationItemSelected wołany przy każdej zmianie wyboru
    • indeks wyboru
    • ID wyboru, jeśli dotyczy
  • każdy wybór wiąże się z pokazaniem odpowiedniego Fragment-u
    • pełnoekranowy fragment dołączamy do android.R.id.content
    • niepełnoekranowy fragment dołączamy do odpowiedniej ViewGroup

public class XActivity extends Activity  {

          ActionBar.OnNavigationListener _navigationListener;

          …

}

public class SimpleNavigationListener  implements ActionBar.OnNavigationListener  {

          …

          public boolean onNavigationItemSelected(int i, long l)  {

                   String fragmentClassName = _fragmentList[i];

                   Fragment theFragment = Fragment.instantiate(_containingActivity, fragmentClassName);

 

                   FragmentTransaction fragmentTransaction = _containigActivity.getFragmentManager(). beginTransaction();

                   fragmentTransaction.replace(android.R.id.content, theFragment);  //lub viewGroupId

                   fragmentTransaction.commit();

 

                   return true;

          }

          public static SimpleNavigationListener SetupListNavigation(Activity containingActivity, …)  {

                   …

                   SimpleNavigationListener listener = new SimpleNavigationListener(containingActivity, …);

 

                   ActionBar actionBar = containingActivity.getActionBar();

 

                   actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);

                   actionBar.setListNavigationCallbacks(displayNameList, listener);

                  

                   actionBar.setDisplayShowTitleEnabled(false);

          }

}

Interaktywność

Widoki akcji - interaktywne widgety, które pokazują się w ActionBar

  • pozwalają pokazywać okazjonalnie używane UI w ActionBar i zaoszczędzić miejsce na ekranie
  • zastępuje pojedynczy element z akcją (może być stale widoczny lub automatycznie być ukrywany i pokazywany)

Definicja w XML

  • specyfikujemy klasę widoku dla elementów menuItem atrybutem actionViewClass
  • można używać większość klas dziedziczących po View (wbudowanych lub własnych)
  • najczęściej używaną klasą jest SearchView (ma wbudowaną świadomość ActionBar)

<menu …>

         <item …

                    android:actionViewClass=”android.widget.SearchView”

</menu>

Własne widoki akcji 

Poprzez zasób z layoutem

  • tak jak każdy zasób dla layoutu
  • wiążemy z menuItem stosując atrybut actionLayout

<menu …>

         <item …

                    android:actionLayout=”@layout/action_view_layout”

</menu>

Pokazywanie i ukrywanie widoków akcji

  • domyślnie widok akcji jest widoczny cały czas
  • możliwość dynamicznego pokazywania i ukrywania
    • w atrybucie showAsAction zawieramy collapseActionView (po naciśnięciu przycisku następuje rozwinięcie do kontrolki)
    • programowo
      • pobieramy referencję na pozycję przy użyciu menu.findItem
      • menuItem.isActionViewExpanded / menuItem.expandActionView / menuItem.collapseActionView
      • odpowiadanie na pokazywanie / ukrywanie
        • implementujemy interfejs onActionExpandListener (możliwość anulowania akcji przez zwrócenie false)
          • boolean onMenuItemActionExpand(MenuItem menuItem)
          • boolean onMenuItemActionCollapse(MenuItem menuItem)
        • wiążemy listener z menuItem metodą setOnActionExpandListener

Dostępność zawartości widoku akcji z poziomu kodu

  • metoda getActionView
    • przy actionViewClass - zwraca referencję na tą klasę
    • przy actionLayout - zwraca główny node layoutu
  • zawartość z widoku akcji jest dostępna poprzez metodę findViewById

TextView

  • setOnEditorActionListener
  • TextView.OnEditorActionListener
    • boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent)

public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent)  {

        if  (keyEvent != null)  {

                 if  (keyEvent.getAction() == KeyEvent.ACTION_DOWN  && keyEvent.getKeyCode() == KeyEvent.KEYCODE_ENTER)  {

                          CharSequence enterText = textView.getText();

                          …

                 }

        }

        return false;

}

Brak komentarzy: