Download menu

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
http://www.android.com/
Menus, themes and ActionBar
Activity communication and Bundle
Shared Preferences
Event handling
More GUI components and Adapters
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
• See the BuildingMenus and ActionBar example
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;
...
Old style
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 code in
/res/menu/my_menu.xml
<?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>
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));
}
XML alt. in BuildingMenus
example
@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");
}
}
Long press the textview
to run onCreateContextMenu
ContextMenu and SubMenu
is created and showed
@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);
}
App Bar (ActionBar or Toolbar)
https://developer.android.com/training/appbar/index.html
The App Bar
ActionBar
Read: http://androiddevelopers.blogspot.se/2012/01/saygoodbye-to-menu-button.html
OptionsMenu with ActionBar
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.activity_main, menu);
return super.onCreateOptionsMenu(menu);
}
<uses-sdk
android:minSdkVersion="11"
android:targetSdkVersion="10" />
<activity
android:parentActivityName="ParentActivity">
</activity>
<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>
@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);
}
Remove the Menu button in an AVD?
Set hw.mainKeys=no in the config.ini file
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
<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>


In: res/values/attrs.xml put the "attr" XML format reference
In: res/menu/menu.xml files give the ”attr” name
<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>
In order to display a theme you must set it before
setContentView(your_layout.xml) is called in your Activity.
If you want your activity to restart, use recreate();
<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);
Toolbar 1
https://github.com/codepath/android_guides/wiki/Using-the-App-ToolBar
• 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/styles.xml
dependencies
compile
compile
compile
compile
compile
}
{
fileTree(include: ['*.jar'], dir: 'libs')
'com.android.support:support-v13:24.2.0'
'com.android.support:design:24.2.0'
'com.google.android.gms:play-services:9.4.0'
'com.android.support:appcompat-v7:24.2.0'
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
</style>
</resources>
Toolbar 2
• Add a Toolbar to your layout


android:fitsSystemWindows="true" ensures that the height of the
activity is calculated correct <android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/toolbar"
/layout/toolbar.xml
android:layout_height="wrap_content"
• Using the Toolbar in an
activity xml layout
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" />
...
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
public boolean onOptionsItemSelected(MenuItem item) {
...
Toolbar 4

Material Settings and Toolbar in 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() {
settings_toolbar.xml
@Override
public void onClick(View v) {
<?xml version="1.0" encoding="utf-8"?>
finish();
<android.support.v7.widget.Toolbar
}
xmlns:android="http://schemas.android.com/apk/res/android"
});
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/toolbar"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
app:navigationContentDescription="@string/abc_action_bar_up_description"
android:background="?attr/colorPrimary"
app:navigationIcon="?attr/homeAsUpIndicator"
app:title="@string/action_settings"
/>
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
https://github.com/codepath/android_guides/wiki/Styles-and-Themes
<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-designfailed-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>
More advanced App Bars 1
• Material Design: App Bar
– https://material.google.com/layout/structure.html#structure-app-bar
More advanced App Bars 2
• Implementing Effective Navigation
– Implement navigation patterns with tabs, swipe views, and
navigation drawer – you must master fragments before use!
– http://developer.android.com/training/implementingnavigation/index.html
Passing a Bundle

What's the correct way to pass a bundle to the activity that is being launched
from the current one?

http://stackoverflow.com/questions/768969/passing-a-bundle-on-startactivity
// 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.
Communication between Activities
with explicit Intents 1
MainActivity – (MainActivity example) – not all code is present here
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");
}
Communication between Activities
with explicit Intents 2
SecondaryActivity - (MainActivity example) – not all code is present here
@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>
</activity>
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
String lastValue_1 = myPrefs.getString(String key, String defaultValue);
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);
}
}
http://developer.android.com/reference/android/app/Activity.html
@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();
}
}
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
and Ringtone - 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/
http://www.vogella.com/articles/AndroidFileBasedPersistence/article.html
Shared Preferences Framework
• Default settings etc. are stored in: res/xml/preferences.xml
• ListPreference store string arrays in: res/values/arrays.xml
Creating a Preference file
• File > New > Other > Android XML 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"/>
</PreferenceCategory>
</PreferenceScreen>
Connecting a ListPreference
• Note that for the ListPreference, an android:entries attribute is
defined
• Example of “res/values/arrays.xml” and working with the earlier
preference file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="low_speed_names">
<item>No threshold</item>
<item>3 km/h</item>
<item>5 km/h (default)</item>
<item>7 km/h</item>
<item>10 km/h</item>
</string-array>
<string-array name="low_speed_values">
<item>-1</item>
<item>3</item>
<item>5</item>
<item>7</item>
<item>10</item>
</string-array>
</resources>
Shared Preferences Framework
• A settings/preference class which extends PreferenceActivity
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);
}
};
}
Using Preference Fragments
• Of course after API 11 settings are fragment based
– http://developer.android.com/guide/topics/ui/settings.html#Fragment
// 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();
}
}
Use the AS Wizard - SettingsActivity
• 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 setting headers and the
corresponding underlying
pref_data_sync.xml,
pref_general.xml and
pref_notification.xml
// 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"));
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
– OnFocusChanged() — Called when the view gains or loses
focus
Event Handlers 2
• Implement the "Press BACK again to exit" Toast user pattern
• User must click the phones back button again within two seconds
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);
}
Event Handlers 3
Physical buttons are
most for programming
games and other specific
usages when events listners
are not available or usable.
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()
because they might not be physical
keys.
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);
}
Example
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
interaction, the MotionEvent delivered to onTouchEvent() provides the
details of every interaction. Your app can use the data provided by the
MotionEvent to determine if a gesture it cares about happened
Detect Touch
• To intercept touch events in an Activity or View, override the
onTouchEvent() callback
/**
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);
}
}
See the touch and gesture
SwiperDiaper example project
Detect Gestures
• Android provides the GestureDetector class for detecting common gestures.
Some of the gestures it supports include onDown(), onLongPress(), onFling()
etc. You can use GestureDetector in conjunction with onTouchEvent()
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);
}
...
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>
spinner_seekbar.xml
spinner_entry.xml
<?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>
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]);
mFavoriteOcean.setAdapter(mAdapter);
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!");
}
});
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();
}
}
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
– Use UI things as OptionsMenu, ActionBar/Toolbar and
AlertDialog etc.