• No results found

w41-42_extra_toolbar.pdf

N/A
N/A
Protected

Academic year: 2020

Share "w41-42_extra_toolbar.pdf"

Copied!
39
0
0

Loading.... (view fulltext now)

Full text

(1)

Menus, themes and ActionBar

Activity communication and Bundle

Shared Preferences

Event handling

More GUI components and Adapters

(2)

Menus

• OptionsMenu

– The main menu for an Activity that displays when the overflow button is pressed. It contains a text menu possibly with icons and an expanded menu when the

more menu item is selected. Old devices may have a menu button

– Some very old apps only have the old menu (long press back button to open...)

• App Bar (Toolbar or ActionBar)

– Enables a consistent way for implementing actions and navigation

– ActionBar can be used from API 11 (from API 7 with v7 appcompat library)

– ToolBar can be used from API 21 (also from API 7 with v7 appcompat library)

• ContextMenu

– A floating list of menu items that displays when a specific Widget/View is long pressed

• SubMenu

– A floating list of menu items that displays when a menu item is pressed

• These types of menus should be made in XML

– They should be put in the app/res/menu/ resources directory

(3)

OptionsMenu with Java

@Override

public boolean onCreateOptionsMenu(Menu menu) {

super.onCreateOptionsMenu(menu);

// Create and add new menu alternatives

// add (int groupId, int itemId, int order, CharSequence title)

MenuItem itemAbout = menu.add(Menu.NONE, VIEW_ABOUT, Menu.NONE, getString(R.string.about));

MenuItem itemDoNothing = menu.add(Menu.NONE, SOMETHING_ELSE, Menu.NONE, R.string.do_nothing);

// Add icons

itemAbout.setIcon(R.drawable.icon);

// Add numeric and alphabetic shortcuts

itemAbout.setShortcut('0', 'o'); // about

itemDoNothing.setShortcut('1', 'i'); // nothing

return true;

}

@Override

public boolean onOptionsItemSelected(MenuItem item) {

super.onOptionsItemSelected(item);

switch (item.getItemId()) {

case (VIEW_ABOUT): {

Intent aboutIntent = new Intent(this, AboutActivity.class); startActivity(aboutIntent); // start the new Activity

return true; ...

(4)

OptionsMenu etc. in XML

@Override

public boolean onCreateOptionsMenu(Menu menu) {

super.onCreateOptionsMenu(menu);

// Returns a MenuInflater with this context

MenuInflater inflater = getMenuInflater();

// Inflate a menu hierarchy from the specified XML resource

inflater.inflate(R.menu.my_menu, menu);

return true;

}

<?xml version="1.0" encoding="utf-8"?>

<menu xmlns:android="http://schemas.android.com/apk/res/android" >

<item

android:id="@+id/menu_about"

android:title="@string/menu_about" android:icon="@drawable/icon" />

<item

android:id="@+id/menu_do_nothing"

android:title="@string/menu_do_nothing"

</menu>

XML code in

(5)

ContextMenu and SubMenu

private String[] choices = {"Press Me", "Try Again", "Change Me"}; @Override

public void onCreate(Bundle savedInstanceState) { ...

bv = (TextView) findViewById(R.id.focus_text);

registerForContextMenu((View) findViewById(R.id.focus_text)); }

@Override

public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo);

if(v.getId() == R.id.focus_text) {

SubMenu textMenu = menu.addSubMenu("Change Text"); textMenu.add(0, ID_TEXT1, 0, choices[0]);

textMenu.add(0, ID_TEXT2, 0, choices[1]); textMenu.add(0, ID_TEXT3, 0, choices[2]); menu.add(0, ID_DEFAULT, 0, "Original Text"); }

}

@Override

public boolean onContextItemSelected(MenuItem item) { switch(item.getItemId()) {

case ID_DEFAULT:

bv.setText(R.string.hello); return true;

case ID_TEXT1: case ID_TEXT2: case ID_TEXT3:

bv.setText(choices[item.getItemId()-1]); return true;

}

return super.onContextItemSelected(item); }

Long press the textview

to run onCreateContextMenu ContextMenu and SubMenu is created and showed

(6)

The App Bar

https://developer.android.com/training/appbar/index.html
(7)

ActionBar

Read:

(8)

OptionsMenu with ActionBar

@Override

public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.activity_main, menu); return super.onCreateOptionsMenu(menu);

}

@Override

public boolean onOptionsItemSelected(MenuItem item) {

ActionBar actionBar = getActionBar(); switch (item.getItemId()) {

case android.R.id.home:

// an app icon in action bar when clicked - go to parent - since API 16 handled by parentActivityName in the AndroidManifest file

// Intent intent = new Intent(this, ParentActivity.class);

// intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); // startActivity(intent);

NavUtils.navigateUpTo(this, new Intent(this, ActionBarExample.class));

return true;

case R.id.menu_actionbar_toggle:

if(visible)

actionBar.hide();

else

actionBar.show();

visible = !visible; return true;

case R.id.menu_hide_navigation:

getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);

return true;

default:

return super.onOptionsItemSelected(item);

} }

<menu xmlns:android="http://schemas.android.com/apk/res/android" >

<item

android:id="@+id/menu_hide_navigation" android:orderInCategory="100"

android:icon="@drawable/robot48"

android:title="@string/menu_hide_navigation" android:showAsAction="ifRoom|withText"/>

<item

android:id="@+id/menu_actionbar_toggle" android:orderInCategory="100"

android:showAsAction="never"

android:title="@string/menu_actionbar_toggle" /> </menu>

<uses-sdk

android:minSdkVersion="11" android:targetSdkVersion="10" /> <activity

android:parentActivityName="ParentActivity"> </activity>

(9)

Style, themes and resources

By adding custom names in the res/values/styles.xml file your

app can have a dark or light theme

– Icons can be XML ”programmed” to automatically change

– Get icons: http://developer.android.com/ > Design > Downloads

In: res/values/attrs.xml put the "attr" XML format reference

In: res/menu/menu.xml files give the ”attr” name

<style name="CustomThemeLight" parent="android:Theme.Holo.Light">

<item name="theme_dependent_icon_upload" >@drawable/ic_action_upload_light</item>

<item name="theme_dependent_icon_share" >@drawable/ic_action_share_light</item> </style>

<style name="CustomThemeDark" parent="android:Theme.Holo">

<item name="theme_dependent_icon_upload" >@drawable/ic_action_upload_dark</item>

<item name="theme_dependent_icon_share" >@drawable/ic_action_share_dark</item> </style>

<resources>

<declare-styleable name="custom_menu">

<attr name="theme_dependent_icon_upload" format="reference"/> <attr name="theme_dependent_icon_share" format="reference"/> </declare-styleable>

</resources>

<item

android:id="@+id/menu_item_share" android:orderInCategory="100"

android:showAsAction="ifRoom|withText"

android:icon="?attr/theme_dependent_icon_share" android:title="@string/menu_item_share"/>

if(lightTheme)

setTheme(R.style.CustomThemeLight);

else

setTheme(R.style.CustomThemeDark); In order to display a theme you must set it before

(10)

Toolbar 1

• The Toolbar is more configurable and a generalization of

the ActionBar system

– Toolbar is a regular View included in a layout like any other View and thereby easier to position, animate and control

– Multiple distinct ToolBar elements can be defined within a single activity

• Using ToolBar as an ActionBar

– Add the v7 support library in the build.gradle (Module:app) file

– Disable the theme-provided ActionBar in res/values/styles.xml dependencies {

compile fileTree(include: ['*.jar'], dir: 'libs') compile 'com.android.support:support-v13:24.2.0'

compile 'com.android.support:design:24.2.0'

compile 'com.google.android.gms:play-services:9.4.0'

compile 'com.android.support:appcompat-v7:24.2.0'

}

<resources>

<!-- Base application theme. -->

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> </style>

</resources>

(11)

Toolbar 2

• Add a Toolbar to your layout

 android:fitsSystemWindows="true" ensures that the height of the activity is calculated correct

 /layout/toolbar.xml

• Using the Toolbar in an

activity xml layout

<android.support.v7.widget.Toolbar

xmlns:android="http://schemas.android.com/apk/res/android"

android:id="@+id/toolbar"

android:layout_height="wrap_content"

android:layout_width="match_parent"

android:fitsSystemWindows="true"

android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"

android:background="?attr/colorPrimaryDark"> </android.support.v7.widget.Toolbar>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:app="http://schemas.android.com/apk/res-auto"

android:layout_width="match_parent" android:layout_height="match_parent"

android:orientation="vertical"> <include

layout="@layout/toolbar"

android:layout_width="match_parent"

android:layout_height="wrap_content" />

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent" android:layout_height="match_parent"

android:focusable="true"

android:focusableInTouchMode="true"> <TextView

android:id="@+id/textStatus"

android:layout_width="wrap_content" android:layout_height="wrap_content"

android:layout_alignParentBottom="true"

android:layout_centerHorizontal="true"

android:text="Status : Not connected"

android:textSize="16sp" />

(12)

Toolbar 3

Use the Toolbar layout...

// when using the support library make sure that you import the following

import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar;

public class MyActivity extends AppCompatActivity { @Override

protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

setContentView(R.layout.activity_my);

// Find the toolbar view inside the activity layout

Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);

// Sets the Toolbar to act as the ActionBar for this Activity window.

// Make sure the toolbar exists in the activity and is not null

if (toolbar != null) {

setSupportActionBar(toolbar); }

}

// Menu icons are inflated just as they were with actionbar

@Override

public boolean onCreateOptionsMenu(Menu menu) {

// Inflate the menu; this adds items to the toolbar if it is present.

getMenuInflater().inflate(R.menu.menu_main, menu);

return true; }

}

// Handle Menu selections as usual as well

@Override

(13)

Toolbar 4

(SettingsActivity fix)

Material Settings and Toolbar with AS Settings Wizard

/**

* MaterialSettings: https://github.com/davcpas1234/MaterialSettings * http://stackoverflow.com/questions/26509180/

no-actionbar-in-preferenceactivity-after-upgrade-to-support-library-v21/27455363#27455363 * @param savedInstanceState

*/ @Override

protected void onPostCreate(Bundle savedInstanceState) {

super.onPostCreate(savedInstanceState);

LinearLayout root = (LinearLayout)findViewById(android.R.id.list).getParent().getParent().getParent(); Toolbar bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false); root.addView(bar, 0); // insert at top

// set correct Toolbar title

if(mPreferenceHeader != null) { bar.setTitle(mPreferenceHeader); }

bar.setNavigationOnClickListener(new View.OnClickListener() { @Override

public void onClick(View v) { finish();

} });

}

<?xml version="1.0" encoding="utf-8"?>

(14)

Themes and colors

https://developer.android.com/training/material/theme.html

• Customize the Color Palette

If you select a specific Theme

• Customize the Status and App Bar

– In styles.xml and colors.xml

<resources>

<!-- inherit from the material theme -->

<style name="AppTheme" parent="android:Theme.Material"> <!-- Main theme colors -->

<!-- your app branding color for the app bar --> <item name="android:colorPrimary">@color/primary</item>

<!-- darker variant for the status bar and contextual app bars --> <item name="android:colorPrimaryDark">@color/primary_dark</item> <!-- theme UI controls like checkboxes and text fields --> <item name="android:colorAccent">@color/accent</item>

<!--

http://stackoverflow.com/questions/26984183/android-material-design-failed-to-find-style-toolbarstyle-in-current-theme -->

<item name="toolbarStyle">@style/Widget.AppCompat.Toolbar</item> </style>

</resources>

<resources>

<!-- http://www.materialpalette.com/ --> <color name="primary">#4CAF50</color> <color name="primary_dark">#388E3C</color> <color name="accent">#8BC34A</color>

</resources>

(15)

More advanced App Bars 1

• Material Design: App Bar

(16)

More advanced App Bars 2

• Implementing Effective Navigation

– Implement navigation patterns with tabs, swipe views, and

navigation drawer – you must master fragments before use!

(17)

Passing a Bundle

// You have a few options

1) Use the Bundle from the Intent

Intent mIntent = new Intent(this, Example.class); Bundle extras = mIntent.getExtras();

extras.putString(key, value);

2) Create a new Bundle

Intent mIntent = new Intent(this, Example.class); Bundle mBundle = new Bundle();

mBundle.putString(key, value); mIntent.putExtras(mBundle);

3) Use the putExtra() shortcut method of the Intent Intent mIntent = new Intent(this, Example.class); mIntent.putExtra(key, value);

// Then, in the launched Activity, you would read them via String value = getIntent().getExtras().getString(key);

NOTE: Bundles have "get" and "put" methods for all the primitive types, advanced Parcelables, and Serializables. I just used Strings for demonstrational purposes.

 What's the correct way to pass a bundle to the activity that is being launched

from the current one?

(18)

Communication between Activities

with explicit Intents 1

public class MainActivity extends Activity implements View.OnClickListener {

// we must implement onClick() since we implements View.OnClickListener interface in our class public void onClick(View view){

//create a new intent and explicit specify that it's target is SecondaryActivity... Intent intent = new Intent(this /*getApplicationContext() or view.getContext()*/,

SecondaryActivity.class);

//load the intent with a key "myKey" and assign it's value //to be whatever has been entered into the text field... intent.putExtra("myKey", mEditText1.getText().toString());

//launch the secondary activity and send the intent along with it //note that a request code is passed in as well so that when the //secondary activity returns control to this activity,

//we can identify the source of the request...

// startActivity(intent); // if we just want to start the other Activity with no return result

startActivityForResult(intent, SECONDARY_ACTIVITY_REQUEST_CODE); }

// we need a handler for when the secondary activity finishes it's work and returns control // to this activity... we don't handle the resultCode Activity.RESULT_OK in this example

@Override

protected void onActivityResult(int requestCode, int resultCode, Intent intent) {

super.onActivityResult(requestCode, resultCode, intent); Bundle extras = intent.getExtras();

mEditText1.setText(extras != null ? extras.getString("returnKey"):"nothing returned"); }

(19)

Communication between Activities

with explicit Intents 2

@Override

public void onCreate(Bundle savedInstanceState) {

if(savedInstanceState != null)// if the activity is being resumed and instancestate have been saved mIntentString = savedInstanceState.getString("myKey");

else

{ // check to see if a Bundle is present, the MainActivity may have called us

Bundle extras = getIntent().getExtras(); // retrieves a map of extended data from the intent if(extras != null){

mIntentString = extras.getString("myKey");// get parameters from the Bundle out of the Intent }

else

mIntentString = "nothing passed in"; // default init }

// set the textbox to display mIntentString mEditText2.setText(mIntentString);

public void onClick(View view){

mIntentString = mEditText2.getText().toString(); //create a new intent...

Intent intent = new Intent();

//add "returnKey" as a key and assign it the value //in the textbox...

intent.putExtra("returnKey", mEditText2.getText().toString()); //get ready to send the result back to the caller (MainActivity) //and put our intent into it (RESULT_OK will tell the caller that //we have successfully accomplished our task..

setResult(Activity.RESULT_OK, intent); //close this Activity...

finish(); }

Remember to create the SecondaryActivity in the AndroidManifest!

<activity android:name=

".SecondaryActivity"

<intent-filter>

<action android:name=

"android.intent.action.VIEW"/> <category android:name=

"android.intent.category.DEFAULT"/> </intent-filter>

(20)

Shared Preferences 1

• Storing and reading current preferences (data) in a simple

Name (Key) – Value pair format can be very handy in your

application

– Saving application/UI settings and other properties to a ”limited Bundle”

– Use with the proper lifecycle methods

– At next invokation/call the App can read the last used values easy

– If the App name is ”se.du.gpsmap" the shared preferences data is stored in a XML file under the /data/data/se.du.gpsmap/shared_prefs directory

– The datatypes: int, long, float, String and boolean are supported

// Either MODE_PRIVATE, MODE_WORLD_READABLE or MODE_WORLD_WRITEABLE

SharedPreferences myPrefs = getSharedPreferences("MyPrefs", Activity.MODE_PRIVATE);

// SharedPreferences myPrefs = PreferenceManager.getDefaultSharedPreferences(this);

// store preference

SharedPreferences.Editor prefsEditor = myPrefs.edit();

prefsEditor.putString("URL_1", urlText.getText().toString());

// You have to commit otherwise the changes will not be remembered

prefsEditor.commit(); // at once, prefsEditor.apply(); will do it in background

// read preference

(21)

Shared Preferences 2

• Data stored with onSaveInstanceState() will only be held in memory until the whole application is closed (no other activity is launched in front of it)

• Save in onPause() before the Activity is “killable” and restore in onCreate() public class SaveActivity extends Activity {

public static final String MY_PREFS = "SaveActivityPrefs"; public static final String TEXT_INPUT = "text_input"; private EditText textInput;

@Override

public void onCreate(Bundle savedInstanceState) {

textInput = (EditText) findViewById(R.id.text_input);

if(savedInstanceState != null) // if the activity is being resumed

{...} else{

// restore UI state from when last run of the application

SharedPreferences settings = getSharedPreferences(MY_PREFS, MODE_PRIVATE); String currentInput = settings.getString(TEXT_INPUT, "");

textInput.setText(currentInput); }

}

@Override

protected void onPause() {

String currentInput = textInput.getText().toString();

// save UI state by getting a SharedPreferences editor

SharedPreferences settings = getSharedPreferences(MY_PREFS, MODE_PRIVATE); SharedPreferences.Editor editor = settings.edit();

editor.putString(TEXT_INPUT, currentInput); editor.commit(); // commit the edits

super.onPause(); }

}

(22)

Shared Preferences Framework

 Android provides a standardized framework for setting preferences across all applications

 The framework uses categories and screens to group related settings

PreferenceCategory is used to declare a set of preferences into one category

PreferenceScreen presents a group of preferences in a new screen

 Possible elements to put preferences in are: CheckBox, EditText,

List, MultiSelectList, Ringtone and Switch - Preference

 The Android system then generates a UI to manipulate the created preferences in the file: res/xml/preferences.xml

 These preferences are stored in shared preferences, which means they can be retrieved by using the getPreference() methods

 Resources which describe the preference framwork

 http://developer.android.com/guide/topics/ui/settings.html

 http://developer.android.com/reference/android/preference/package-summary.html  http://www.javacodegeeks.com/2011/01/android-quick-preferences-tutorial.html  http://viralpatel.net/blogs/android-preferences-activity-example/

(23)

Shared Preferences Framework

(24)

Creating a Preference file

• Right click res/xml > New > XML Resource File

Example content

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" > <PreferenceCategory android:title="@string/prefcat_general_title1" >

<EditTextPreference

android:defaultValue="@string/pref_ueid_default" android:key="@string/pref_ueid"

android:summary="@string/pref_ueid_summary"

android:title="@string/pref_ueid_title" />

<ListPreference

android:defaultValue="@string/pref_low_speed_default" android:entries="@array/low_speed_names"

android:entryValues="@array/low_speed_values" android:key="@string/pref_low_speed"

android:summary="@string/pref_low_speed_summary"

android:title="@string/pref_low_speed_title" /> </PreferenceCategory>

<PreferenceCategory android:title="@string/prefcat_general_title2">

<CheckBoxPreference

android:key="@string/pref_admin_developer_mode"

android:defaultValue="@string/pref_admin_developer_mode_default" android:title="@string/pref_admin_developer_mode_title"

android:summary="@string/pref_admin_developer_mode_summary"

android:selectable="false"/>

<EditTextPreference

android:defaultValue="@string/pref_http_server_url_default" android:key="@string/pref_http_server_url"

android:summary="@string/pref_http_server_url_summary" android:title="@string/pref_http_server_url_title"

android:dependency="@string/pref_admin_developer_mode"/>

<CheckBoxPreference android:key="@string/pref_use_encryption"

android:defaultValue="@string/pref_use_encryption_default" android:title="@string/pref_use_encryption_title"

android:summary="@string/pref_use_encryption_summary"

android:dependency="@string/pref_admin_developer_mode"/>

(25)

Connecting a ListPreference

• Note that for the ListPreference, android:entries attribute are

defined

• Example of “res/values/arrays.xml” and working with the

preference XML file via UI

<?xml version="1.0" encoding="utf-8"?>

<resources>

<string-array name="locale_names"> <item>Automatic (default)</item> <item>English</item>

<item>Swedish</item> </string-array>

<string-array name="locale_values"> <item></item>

<item>en</item> <item>se</item> </string-array> <string-array

name="video_resolution_names">

<item>480p (480x800), 2.5 Mbps, 30 fps (default)</item>

<item>720p (720x1280), 5 Mbps, 30 fps</item>

</string-array> <string-array

name="video_resolution_values"> <item>480</item>

(26)

Shared Preferences Framework

public class MyPreferences extends PreferenceActivity {

private SharedPreferences myPrefs;

private OnSharedPreferenceChangeListener mSPListener;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

Log.d(Consts.TAG, "MyPreferences onCreate executes ..."); addPreferencesFromResource(R.xml.preferences);

// gets a SharedPreferences instance that points to the default file // that is used by the preference framework in the given context myPrefs = PreferenceManager.getDefaultSharedPreferences(this);

// View all current preferences and values in logcat

Map<String,?> localMap = myPrefs.getAll(); Log.d(Consts.TAG, localMap.toString());

// Use instance field for listener

// It will not be gc'd as long as this instance is kept referenced

mSPListener = new SharedPreferences.OnSharedPreferenceChangeListener() {

@Override

public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {

Log.d(Consts.TAG, "pref changed: " + key); }

}; }

(27)

Using Preference Fragments

// Fragments provide a more flexible architecture for your application, compared // to using activities alone, no matter what kind of activity you're building public static class SettingsFragment extends PreferenceFragment {

@Override

public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

// Load the preferences from an XML resource addPreferencesFromResource(R.xml.preferences); }

... }

// you can then add this fragment to an Activity just // as you would for any other Fragment

public class SettingsActivity extends Activity { @Override

protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

// Display the fragment as the main content // Return the FragmentManager for interacting with // fragments associated with this activity

getFragmentManager()

// Start a series of edit operations on the // Fragments associated with this FragmentManager

.beginTransaction()

.replace(android.R.id.content,

new SettingsFragment()).commit(); }

}

• Of course after API 11 settings are fragment based

(28)

Use the AS Wizard - SettingsActivity

// If you choose to use this settings framwork you must be able to extend/edit the XML and code a little bit. Specifically the note the methods:

public Preference findPreference (CharSequence key) // Finds a Preference based on its key

private static void bindPreferenceSummaryToValue(Preference preference) // Binds a preference's summary to its value

// Bind the summaries of EditText/List/Dialog/Ringtone preferences // to their values. When their values change, their summaries are // updated to reflect the new value, per the Android Design guidelines. bindPreferenceSummaryToValue(findPreference("example_text"));

bindPreferenceSummaryToValue(findPreference("example_list"));

• May make things a bit advanced/complicated?

• Wizard adds fragment (two pane) adaptable code (prev. slide)

– Java

• SettingsActivity which extends from AppCompatPreferenceActivity

– XML

• pref_headers.xml which contains tablet setting headers and the corresponding underlying

– pref_data_sync.xml,

– pref_general.xml and

– pref_notification.xml

(29)

Event Handlers 1

• Most user interaction with an Android device is captured

by the system and sent to a corresponding callback

method

– For example, if the physical Back button is pressed, the onBackPressed() method is called

– Event listeners as View.OnClickListener() etc. are however the preferred method when available because they avoid the class extension overhead

• The system first sends any KeyEvent to the appropriate

callback method in the in-focus activity or view

Callbacks

– onKeyUp(), onKeyDown(), onKeyLongPress() — Physical key press callbacks

– onTrackballEvent(), onTouchEvent() — Trackball and touchscreen press callbacks

(30)

Event Handlers 2

private boolean doubleBackToExitPressedOnce = false;

/** Called when the activity has detected the user's press of the back key. The default implementation simply finishes the current activity, but you can override this to do whatever you want. */

@Override

public void onBackPressed() {

if (doubleBackToExitPressedOnce) { super.onBackPressed();

return; }

this.doubleBackToExitPressedOnce = true;

Utils.showToastMessage(this, "Press BACK again to exit");

// Causes the Runnable r to be added to the message queue, to be run after the specified amount // of time elapses. The runnable will be run on the thread to which this handler is attached.

new Handler().postDelayed(new Runnable() {

@Override

public void run() {

doubleBackToExitPressedOnce = false; }

}, 2000); }

(31)

Event Handlers 3

public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_CAMERA) {

return true;

// consume event, hence do nothing on camera button

}

// let event propagate in class tree

return super.onKeyDown(keyCode, event); }

Physical buttons are most for programming games and other specific usages when events listners are not available or usable.

Example

The Power button, RECENTS and HOME key are intercepted by the system and do not reach the application.

Some buttons as the BACK key should intercept onKeyUp()

(32)

Detect Touch and Gestures

• A "touch gesture" occurs when a user places one or more fingers on the touch screen, and your application interprets that pattern of

touches as a particular gesture

 There are correspondingly two phases to gesture detection

1. Gathering data about touch events

2. Interpreting the data to see if it meets the criteria for any of the gestures your app supports

 Gather Data

 When a user places one or more fingers on the screen, this triggers the

callback onTouchEvent() on the View that received the touch events. For each sequence of touch events (position, pressure, size, addition of

another finger, etc.) that is ultimately identified as a gesture, onTouchEvent() is fired several times

 The gesture starts when the user first touches the screen, continues as the

system tracks the position of the user's finger(s), and ends by capturing the final event of the user's fingers leaving the screen. Throughout this

(33)

Detect Touch

/**

http://www.vogella.com/tutorials/AndroidTouch/article.html https://developer.android.com/training/gestures/detector.html */

@Override

public boolean onTouchEvent(MotionEvent event) {

// get pointer index from the event object int pointerIndex = event.getActionIndex(); // get pointer ID

int pointerId = event.getPointerId(pointerIndex); // get masked (not specific to a pointer) action int action = event.getActionMasked();

switch(action) {

case (MotionEvent.ACTION_DOWN) : Log.d(TAG,"Action was DOWN"); return true;

case (MotionEvent.ACTION_MOVE) : Log.d(TAG, "Action was MOVE"); return true;

case (MotionEvent.ACTION_UP) : Log.d(TAG,"Action was UP"); return true;

case (MotionEvent.ACTION_CANCEL) : Log.d(TAG,"Action was CANCEL"); return true;

case (MotionEvent.ACTION_OUTSIDE) :

Log.d(TAG,"Movement occurred outside bounds " + "of current screen element"); return true;

default :

return super.onTouchEvent(event); }

}

• To intercept touch events in an Activity or View, override the onTouchEvent() callback

(34)

Detect Gestures

public class MainActivity extends Activity implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener {

private static final String TAG = MainActivity.class.getSimpleName(); private TextView textMessage;

private GestureDetector mGestureDetector; @Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

// Instantiate the gesture detector with the application context and an implementation of GestureDetector.OnGestureListener mGestureDetector = new GestureDetector(this, this);

// Set the gesture detector as the double tap listener.

mGestureDetector.setOnDoubleTapListener(this);

textMessage = (TextView)findViewById(R.id.textMessage); }

@Override

public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {

Log.d(TAG,"onScroll: " + motionEvent.toString());

textMessage.setText("onScroll");

return true;

}

@Override

public boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {

Log.d(TAG,"onFling: " + motionEvent.toString());

textMessage.setText("onFling");

return true;

}

@Override

public boolean onTouchEvent(MotionEvent event) {

// Analyzes the given motion event and if applicable triggers the appropriate callbacks on the GestureDetector.OnGestureListener supplied mGestureDetector.onTouchEvent(event);

// Be sure to call the superclass implementation

return super.onTouchEvent(event); }

...

(35)

Seekbar and Spinner

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="fill_parent" android:layout_height="fill_parent"

android:padding="10px" android:orientation="vertical">

<SeekBar android:layout_height="wrap_content" android:id="@+id/seekBar1"

android:layout_marginBottom="15px" android:layout_width="fill_parent" /> <Spinner android:id="@+id/spinner" android:prompt="@string/ocean_prompt"

android:layout_marginTop="15px"

android:layout_height="wrap_content" android:layout_width="fill_parent" /> </LinearLayout>

<?xml version="1.0" encoding="utf-8"?>

<TextView xmlns:android="http://schemas.android.com/apk/res/android"

android:gravity="center" android:textColor="#000"

android:textSize="40sp"

android:layout_width="fill_parent"

android:layout_height="wrap_content"> </TextView>

(36)

Adapters 1

• An Adapter represents a bridge between data (such as an

array or list) and a View (such as a ListView or a Spinner)

• The Adapter creates the child views representing

individual data

• The adapter automatically updates the view(s) if the

underlying data is changed

// create a list/array

private static final String[] mOceans = { "Pacific", "Atlantic", "Indian", "Arctic", "Southern" };

// bind the array to the spinner

mFavoriteOcean = (Spinner) findViewById(R.id.spinner);

ArrayAdapter<String> mAdapter = new ArrayAdapter<String>(this, R.layout.spinner_entry);

mAdapter.setDropDownViewResource(R.layout.spinner_entry);

for(int idx=0; idx<mOceans.length; idx++)

mAdapter.add(mOceans[idx]);

(37)

Adapters 2

• The listener can access underlying data via the adapter

• A spinner does not support item click events. Calling this

method will raise an exception. You must use

OnItemSelectedListener() instead

mFavoriteOcean.setOnItemSelectedListener(new OnItemSelectedListener() {

@Override

public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

showToastMessage("Spinner: " +

parent.getItemAtPosition(position).toString()); }

@Override

public void onNothingSelected(AdapterView<?> parent) { showToastMessage("Spinner onNothingSelected!"); }

(38)

Seekbar, Spinner and ArrayAdapter

public class UITest extends Activity {

private static final String[] mOceans = { "Pacific", "Atlantic", "Indian", "Arctic", "Southern" }; private SeekBar mSeekbar;

private Spinner mFavoriteOcean; @Override

public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

setContentView(R.layout.spinner_seekbar); mFavoriteOcean = (Spinner) findViewById(R.id.spinner);

ArrayAdapter<String> mAdapter = new ArrayAdapter<String>(this, R.layout.spinner_entry); mAdapter.setDropDownViewResource(R.layout.spinner_entry);

for(int idx=0; idx<mOceans.length; idx++)

mAdapter.add(mOceans[idx]);

mFavoriteOcean.setAdapter(mAdapter);

mFavoriteOcean.setOnItemSelectedListener(new OnItemSelectedListener() { @Override

public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { showToastMessage("Spinner: " + parent.getItemAtPosition(position).toString()); }

@Override

public void onNothingSelected(AdapterView<?> parent) { showToastMessage("Spinner onNothingSelected!"); }

});

mSeekbar = (SeekBar) findViewById(R.id.seekBar1); mSeekbar.setProgress(50);

mSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {

public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

if(fromUser){

//showToastMessage("SeekBar: " + progress);

mTV1.setText("SeekBar: " + progress); }

}

public void onStartTrackingTouch(SeekBar seekBar) {}

public void onStopTrackingTouch(SeekBar seekBar) {} });

}

private void showToastMessage(String msg){

Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); }

(39)

Lab review - Android Lab2

List with topics you need to understand before next

laboration

You must be able or know how to

– Understand all the previous points from former labs

– Make a ”new” app from scratch on your own with ”recepies” (solutions) from other apps

– Manage View.OnClickListener touch events (anyone of the 4 button event methods)

– Create additional Activities in an app

– Manage SharedPreferences in a PreferenceActivity

– Understand and be able to use the lifecycle methods plus the onRestoreInstanceState and onSaveInstanceState methods

References

Related documents

whether or not this loan is granted. If there are important changes, I will notify the credit union in writing immediately. I understand that my false statements, or

The NEC EliteMail VMP systems simplify message taking by allowing you to transfer a call directly to a user’s voice mailbox where they will hear the personal greeting and be prompted

Regardless of form (whether it be dross, spills, clean turnings, contaminated turnings or pigs) Behr Iron &amp; Metal has a processing method specific to your Babbitt scrap..

We tend to want to center justify our text, but word in the graphic design community is that left or right justifying your text is the best practice: best for design, best

[r]

The main objective of this study was to evaluate the biomechanical stress generated on the tibialis posterior tendon, the plantar fascia and the spring ligament in different

The default mode is Off.Off = Record 1 large video file stop recording when out of micro SD space or video file size reaches 4GB3, 5, 10 Minutes = Record the video file for

To evaluate the performance of the best catalyst developed for the photocatalytic degradation of phenol in the batch reactor under a wide range of process parameters,