Android course GUI dr Milan Vidaković Chair of Informatics Faculty of Technical Sciences University...

Preview:

Citation preview

Android course

GUI

dr Milan VidakovićChair of Informatics

Faculty of Technical SciencesUniversity of Novi Sad

2/56

GUI elements

Components (view, widgets, home-screen widgets) layouts events resources menus other activities invocation dialogs adapters AsyncTask and Threads

3/56

Views ViewGroup is the root class for the layout containers

which hold View components as subelements and define their position on the screen

View is the root element for all GUI components. It is a rectangle object on the screen which draws its content on the screen and handles GUI events View components are organised as a tree-like structure View components can be defined in the xml layout file or

programmatically

4/56

Widgets

• The other name for GUI components:• form widgets (TextView, Button, ToggleButton,

itd.)• text widgets (EditText,DatePicker, itd.)• composite widgets (ListView, GridView, itd.)• advanced widgets (SurfaceView, ZoomControls)

• Terminology problem: home-screen widgets are special GUI components which are placed on the desktop (or home-screen)

5/56

Form components

• To interact with user• TextView draws text on screen• Button can be pressed (press or click or tap)• ToggleButton is a button which has two states

(on/off)• CheckBox, RadioButton• Spinner – equivalent to the ComboBox (drop down)• RatingBar – draws a value as an array of stars• ProgressBar

6/56

Button, ToggleButton• How to react on click (tap):btnBig.setOnClickListener(new OnClickListener() { public void onClick(View v) { // WRITE YOUR CODE HERE }});• Alterative way:

• android:onClick=“myMethod" in the Button tag, in the layout XML file

• create this method in the activitypublic void myMethod(View view) {• ToggleButton state can be found usig this:tglBtn.isChecked()

ComponentExamples

7/56

Spinner

Spinner – a kind of a drop down (Combo Box). Contains a header which displays currently

selected option and a window which holds all the options.

ArrayAdapter – special class that feeds the spinner. contains data that will be displayed

onItemSelectedListener – callback function that reacts on option selection.

8/56

Text widgets

• EditText component has approx. 30 subtypes. inputType attribute defines those subtypes:• textPassword• textEmailAddress• textMultiLine• date

• AutoCompleteTextView – automatically completes user input• based on the list of accepted valuesnudi mogućnost automatskog

dopunjavanja teksta, na osnovu spiska reči• MultiAutoCompleteTextView – similar to the component

above – allows multiple words to be chosen, and puts the delimiter between them

9/56

AutoCompleteTextViewprivate static final String[] COUNTRIES = new String[] { "Belgium", "Bulgaria", "France", "Italy", "Germany", "Spain", "Sweden"};private void setAutoComplete() { ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, COUNTRIES); AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.autoCompleteTextView1); textView.setAdapter(adapter);}

10/56

MultiAutoCompleteTextViewprivate static final String[] COUNTRIES = new String[] { "Belgium", "Bulgaria", "France", "Italy", "Germany", "Spain", "Sweden“};

private void setMultiAutoComplete() { ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, COUNTRIES); MultiAutoCompleteTextView textView =

(MultiAutoCompleteTextView) findViewById(R.id.multiAutoCompleteTextView1);

textView.setAdapter(adapter); textView.setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer());}

11/56

Composite widgets

List View – displays data in a list Grid View – displays data in a table ScrollView – provides scrolling capability to

views which have more data than can be displayed

Web View – displays web pages Gallery – displays images Google Map View – displays Google map

12/56

ListView Displays data in a list

data comes from: hardcoded values in the code, database, or custom source

setListAdapter method links ListView to data data is placed in the Adapter component

onListItemClick – callback finction which is invoked when user clicks on an item

ListActivity – customised activity which holds one ListView

ListViewExamples

13/56

ListView data item display

• There are system components for data item display:

this.setListAdapter( new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,names));

• Or, to make custom viewer for one row of data

14/56

GridView

• Displays data in a table• Data is placed in an adapter:gv.setAdapter(new ArrayAdapter<String>(this,

android.R.layout.simple_list_item_1, PLANETS));• OnItemClickListener.onItemClick() callback invoked

when clicked on an itemGridViewExamples

15/56

ScrollView

• If the number of items in a view is so big that only a fraction can be displayed, this component should hold the view as a subcomponent

• There can be only one direct subcomponent (of layout type):• ScrollView

• LinearLayout• TextView• TextView,• ...

ListViewExamples

16/56

WebView

• Displays web page• JavaScript is turned off by default and there is no error

handling• instead of using this component, a “real“ browser can be

used:Uri uri = Uri.parse("http://www.example.com");Intent intent = new Intent(Intent.ACTION_VIEW, uri);startActivity(intent);

WebViewExamples

17/56

WebView

• A page is loaded by invoking the loadUrl() method:

web.loadUrl(“http://www.google.com”);

• Needs to add the following permission in the AndroidManifest.xml file:

<uses-permission android:name="android.permission.INTERNET" />

18/56

WebView

• Instead of HTML page, this component can display a string containing HTML:

String summary = "<html><body>Hello <b>World</b>.</body></html>";

webview.loadData(summary, "text/html", "utf-8");

19/56

Home-screen widgets

• Components which are placed on the desktop• Thay are installed on the desktop• There is a desktop process, but these

components are not part of tha t process• they are separated from the desktop process in

order to save it when they crash• System can call this component periodically

20/56

Layouts

• Layouts place components on the screen according to their internal logic

• One activity can have one or more layouts• layouts can be combined (one layout inside other)

LayoutExamples

21/56

Layouts

Linear Layout

Relative Layout

Table Layout

Tab Layout

22/56

FrameLayout

• Displays single component all over the window

23/56

LinearLayout

• Puts components in a row or column (horizontal, or vertical)• there is an attribute: android:orientation = "vertical“ which sets the

orientation• When adding component in the LinearLayout, following attributs are

important: • android:layout_width and android:layout_heigth define width and height of a

component• match_parent (replaced the old fill_parent) – means: use the whole space for the

component• wrap_content – don’t use the whole space

• layout_weight – sum of all weights is equal to 1; individual weight defines percentage of a space used for that component

• Margin:android:padding=“2dip”

24/56

LinearLayout

• android:gravity attribute can be understood as an alignment:• top or bottom – set the object at the top or bottom of a

container, and keep the dimensions• left or right – set the object left or right in the container,

and keep the dimensions• center_vertical – put it in a center (vertically), and keep

the dimensions• fill_vertical – grow vertically until the container is filled• center – place it in a center (both vert. and horiz.), and

keep the dimensions

25/56

RelativeLayout

• Components are placed relative to each other• Ignores the gravity attribute• Following attributes have the value of an ID of a

component to which the component is placed: • layout_below, layout_above, etc. define postion relative

to the component which ID is given (layout_below=“@id/textView1”)

• layout_toRightOf, layout_toLeftOf• layout_alignTop, layout_alignRight

26/56

TableLayout• Displays components in a table• Components are added in rows (inside the TableRow tag)

• alignment of components in cells are defined with the android:gravity attribute• the number of added components define the number of cells in a row

• Merge two cells by using the following attribute: android:layout_span="2" • Components are placed in cells from left to right

• if a component needs to pbe placed in a different row that the one it should be, the following attribute will be used:

android:layout_column=“2”

27/56

TabLayout

• Puts several activities on a single window and makes them selectable by clicking on a tab above each activity

• TabActivity class inherits Activity class and holds all the tabs

• When designing each tab, in the layout file, the TabHost tag is used• it holds the TabWidget tag for tabs and FrameLayout for the

content• TabSpec class defines various parameters for tabs

(name, icon, etc.)

28/56

Events

• Android GUI applications react on various GUI events• Click (tap) on the control generates an evente which

can will be handled by the appropriate Listener• For example, if we tap on the button, that event will

be handled this way:btnFrame.setOnClickListener(new

View.OnClickListener() { public void onClick(View v) { // WRITE YOUR CODE HERE }});

29/56

Resources

• res folder in a project contains resources• Resources can be:– animation –anim folder– lists of used colors –color folder– multimedia (pictures, animations, etc.) –drawable folder– the rest –raw folder

• android.resource://com.blast/raw/famous

– xml files which define GUI –layout folder• Resource names must be made with lower case letters (with

the optional ‘_’ character)

30/56

Menu

Options Menu – invoked by clicking on the system menu button onCreateOptionsMenu(menu) callback method is used to add items to the

menu onMenuItemSelected(featureId, menuItem) callback method is invoked when

user selects an item

Context Menu – the equivalent of the context menu (right click menu on desktop computers) registerForContextMenu(component) method registers the context menu for a

given component onCreateContextMenu(menu, view, contextMenuInfo) callback method is used

to add items to the menu onContextItemSelected(menuItem) callback method is invoked when users

selects an item MenuExamples

31/56

Options menu

• Adding items:@Overridepublic boolean onCreateOptionsMenu(Menu menu) {

super.onCreateOptionsMenu(menu); menu.add(0, OPTIONS_MENU_ADD_ID, 0, R.string.options_menu_add); return true;}

32/56

Options menu

• How to react when an item is selected:@Overridepublic boolean onMenuItemSelected(int featureId,

MenuItem item) { switch (item.getItemId()) { case OPTIONS_MENU_ADD_ID: // TODO return true; } return super.onMenuItemSelected(featureId, item);}

33/56

Context menu

• Creating context menu:registerForContextMenu(komponenta);

if an activity extends ListActivity, then it is done this way:registerForContextMenu(getListView());• Adding items: public void onCreateContextMenu(ContextMenu menu, View v,ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); menu.add(0, DELETE_ID, 0, R.string.v3_menu_delete);}

34/56

Context menu

• How to figuer out which item was selected• Us the callback method: boolean onContextItemSelected(MenuItem item) {AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();

Log.d("V3", „Item Id: " + info.id + ", position: “ + info.position);

}

35/56

Invoke other activity

Create an Intent and then invoke on of the two following methods: startActivity(Intent intent) or startActivityForResult(Intent intent, int requestCode)

The first method invoks activity and does not expect the result from it

Invoked activity can call the finish() method to go back, but it is sufficient to click on the Back button on the device

36/56

Invoke other activity

How to pass some data to the other activity:Object o = this.getListAdapter().getItem(position);selectedCity = o.toString();// Toast.makeText(this, "You selected: " + selectedCity,

Toast.LENGTH_LONG).show();Intent i = new Intent(this, AnotherActivity.class);i.putExtra("com.blast.CITY", selectedCity);startActivityForResult(i, EDIT_ID);

• How does the invoked activity fetch that data:Bundle extras = getIntent().getExtras();city = extras != null ?

extras.getString("com.blast.CITY"): null;

37/56

Invoke other activity, but expect a result from it

The result of the other activity work is fetched in the following callback method (written in the main activity):

protected void onActivityResult(int requestCode, int resultCode,

Intent intent)

In the invoked activity, the result code is set and the return intent is created and set:

Intent i = new Intent();

Bundle b = new Bundle();

city = editCity.getText().toString();

b.putString("com.blast.CITY", city);

i.putExtras(b);

setResult(RESULT_OK, i);

finish();

return Intent from the other activity

38/56

The main activity fetches the data in the following callback method:

@Override

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

super.onActivityResult(requestCode, resultCode, intent);

if (resultCode == RESULT_OK) {

...

}

}

Invoke other activity, but expect a result from it

39/56

Dialogs

• To communicate with user– background (main) activity looses focus. A dialog takes over the

control

• Dialog types:– System dialogs– Custom dialogs

• System dialogs:– AlertDialog

invoked when typed: Activity.showDialog(ID) onCreateDialog(ID) callback method creates a dialog

– ProgressDialog setProgress(int) sets the progress value

DialogExamples

40/56

Custom dialogs

• The layout of the dialog is defined in the appropriate file in the res/layout folder

• Extends the Dialog class and sets the layout in the constructor (setContentView() method)

• From the main activity:bd = new BigDialog(this);bd.show();• All the listeners for dialog GUI components are written

in the main activity:Button btnClose =

(Button)bd.findViewById(R.id.btnDialogBigClose);

41/56

Custom dialogs

• Dialog can be created using the builder:AlertDialog.Builder builder = new AlertDialog.Builder(main_activity);builder.setMessage("Are you sure you want to DELETE city “+

getListAdapter().getItem(info.position) + "?");builder.setCancelable(false);builder.setPositiveButton("Yes“, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { Toast.makeText(ComplexAppActivity3.this, "DELETING city “ +

l.getItem(info.position), Toast.LENGTH_LONG).show(); }});builder.setNegativeButton("No“, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); }});dialog = builder.create();

42/56

Notifications

• Status Bar Notification– if we tap on the message, the system will remove

it and can invoke some activity (if defined)• Toast – a text which will be displayed for some

short period of time– makeText(roditelj, tekst, dužina) method returns a

reference to a Toast message– show() displays a message

43/56

Adapters

• Adapters link components and data• components are usually those of the list types

(ListView, GridView, Spinner, etc.)• Adapters hold only the visible portion of data

44/56

Filling the adapter

• Several types:• static list of string from resources• an array of strings from the code• dynamically, from the code

45/56

Filling the adapter with static text

• Create the appropriate xml file in the res/values folder:<?xml version="1.0" encoding="utf-8"?><resources><string-array name="planets_array"> <item>Mercury</item> <item>Venus</item></string-array></resources>• Create an adapter with this static text:ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.planets_array, android.R.layout.simple_spinner_item);

listView.setAdapter(adapter);

ListViewExamples

46/56

Filling the adapter with an array of strings

• Create an adapter:private static final String[] COUNTRIES = new String[]

{ "Belgium", "France", "Italy", "Germany", "Spain" };...ArrayAdapter<String> adapter = new

ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, COUNTRIES);

listView.setAdapter(adapter);

47/56

Filling the adapter from the collection

• Create a collection and pass it to the constructor on an adapter:

ArrayList<String> cities = new ArrayList<String>(); cities.add(“Novi Sad”);cities.add(“Beograd”);

ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, cities);

listView.setAdapter(adapter);

48/56

Displaying single row in a list

• System viewers fo a row (android.R.layout):• activity_list_item• browser_link_context_header• expandable_list_content• list_content• preference_category• select_dialog_item• select_dialog_multichoice• select_dialog_singlechoice• simple_dropdown_item_1line• simple_expandable_list_item_1• simple_expandable_list_item_2

49/56

Displaying single row in a list

• System viewers fo a row (android.R.layout):• simple_gallery_item• simple_list_item_1• simple_list_item_2• simple_list_item_activated_1• simple_list_item_activated_2• simple_list_item_checked• simple_list_item_multiple_choice• simple_list_item_single_choice• simple_selectable_list_item• simple_spinner_dropdown_item• simple_spinner_item• test_list_item• two_line_list_item

50/56

List items as objects

• What if we want to fill the adapter with some objects which are not strings?• a list row should have multiple rows• we will create a custom row viewer

(res/layout/custom_single_row.xml)• we will create a custom ArrayAdapter

• we will extend the ArrayAdapter class and override at least getView() method• this method returns a row viewer component

51/56

Custom Adapter@Overridepublic View getView(int position, View rowView, ViewGroup parent) { CityHolder holder = null; View row = rowView; if(row == null) { LayoutInflater inflater = ((Activity)context).getLayoutInflater(); row = inflater.inflate(textViewResourceId, parent, false); holder = new CityHolder(); holder.txtViewZip = (TextView)row.findViewById(R.id.textZip); holder.txtViewName = (TextView)row.findViewById(R.id.textName); row.setTag(holder); } else { holder = (CityHolder)row.getTag(); } City city = cities.get(position); holder.txtViewZip.setText(city.getZipCode()); holder.txtViewName.setText(city.getName()); return row;}

class CityHolder { TextView txtViewZip; TextView txtViewName;}class City { String zipCode; String name;}

52/56

Changing GUI components

• Each listener is executed in the UI thread– if we make a long-running code in the listener, it will make our

application unresponsive and Android will offer to terminate the application

• Solution:– use standard Java threads (Thread class or Runnable interface)

• drawback – cannot modify GUI components from this therad (progress bar changing, for example)– if that is needed, the Handler class is used to change GUI components

– use the AsyncTask class, which is made for this purpose and can change GUI components• it is executed in a separate thread when processing, but joins the UI thread when

changing GUI components

AsyncTaskExamples

53/56

Standard Java thread

• Changing the GUI components via Handler class:handler.post(new Runnable() { @Override public void run() { pBar.setProgress(count); }});• An attempt to change GUI component without

Handler would crash the application!

54/56

AsyncTask class• Extends the AsyncTask class and override at least the doInBackground

method:@Overrideprotected Integer doInBackground(Integer... params) { int start = params[0]; for (int i = start; i <= 5; i++) { ... publishProgress(count); return count;}

• No need for Handler when changing GUI components• Started by invoking the execute(param) method:ProgressBarTask task = new ProgressBarTask();task.execute(1);

55/56

AsyncTask class

• When extending the AsyncTask class, there are three generics:

class ProgressBarTask extends AsyncTask<Integer, Integer, Integer> {– the first generics is the input type (the type of the execute()

method argument)– the second generics is the type of the intermediate parameter,

which describes current progress in processing (used at the publishProgress() method)

– the third generics is used to define the type of the result (used with the return keyword in the doInBackground() method)

56/56

AsyncTask class• Except doInBackground() method, we can override following methods:

– onProgressUpdate(), invoked from the doInBackground() method by calling the publishProgress() method, which is used to change GUI

@Overrideprotected void onProgressUpdate(Integer ... value) { int current = value[0]; pBar.setProgress(current);}

– onPostExecute(), invoked from the doInBackground() method by returning the result: return (result);

@Overrideprotected void onPostExecute(Integer result) { Toast.makeText(getApplicationContext(), "Job completed: "

+ result, Toast.LENGTH_LONG).show();}

Recommended