Components of a Screen

The basic unit of an Android application is an activity, which displays the UI of your application.

  • The activity may contain widgets such as buttons, labels, textboxes, and so on

Typically, you define your UI using an XML file

  • for example, the activity_main.xml file located in the res/layout folder of your project.

  • During compilation, each element in the XML file is compiled into its equivalent Android GUI (Graphical User Interface) class, with attributes represented by methods

  • The Android system then creates the activity’s UI when the activity is loaded.

Views and ViewGroups

An activity contains Views and ViewGroups.

  • View
    • a widget that has an appearance on screen
    • derives from the base class android.view.View
    • Basic views - Commonly used views:
      • TextView, EditText, Button, ImageButton, CheckBox, ToggleButton, RadioButton, RadioGroup
      • These basic views enable you to display text information / perform some basic selection
    • List views - Views that display a long list of items (User Interface with Views)
      • ListView, SpinnerView etc
  • ViewGroup (is a special type of View)
    • One or more views can be grouped into a ViewGroup
    • provides the layout in which you can order the appearance and sequence of views
      • FrameLayout, LinearLayout, TableLayout, RelativeLayout etc.
    • derives from the base class android.view.ViewGroup

Views - Basic Views

TextView - to display text to the user

Example: TextView Id is txtTitle

1
2
3
TextView txtTitle = findViewById(R.id.txtTitle);
String oldText = txtTitle.getText().toString();
txtTitle.setText("New text");

EditText - allows user to edit the text displayed

Example: EditText Id is editName

1
2
EditText editName = findViewById(R.id.editName);
String name = editName.getText().toString();

There are many types of EditText provided with formatting (e.g. Numbers only, Password etc)

Button - represents a push-button

Example: Button Id is btnSubmit

1
2
3
4
5
6
7
Button btnSubmit = findViewById(R.id.btnSubmit);
btnSubmit.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
//Perform action when button is clicked
}
}

ImageButton - a Button that displays as an image

Example: ImageButton Id is ibtnSubmit

1
2
3
4
5
6
7
8
ImageButton ibtnSubmit = findViewById(R.id.ibtnSubmit);
ibtnSubmit.setImageResource(R.drawable.ic_launcher_round);
ibtnSubmit.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
//Perform action when button is clicked
}
}

CheckBox - a special type of Button that has 2 states:

Example: CheckBox Id is boxCheck

1
2
3
4
5
6
7
CheckBox boxCheck = findViewById(R.id.boxCheck);
boxCheck.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked){
//Perform action when checked or unchecked
}
});

ToggleButton - displays on/off states

Example: ToggleButton Id is btnToggle

1
2
3
4
5
6
7
8
9
ToggleButton btnToggle = findViewById(R.id.btnToggle);
btnToggle.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
if(((ToggleButton)v).isChecked()){
//Perform action when button is clicked
}
}
});

RadioButton & RadioGroup

  • RadioButton has 2 states: Checked or unchecked
  • RadioGroup is used to group on or more RadioButtons, thereby allowing only one RadioButton to be checked within the RadioGroup

Example: RadioGroup Id is group, 2 RadioButtons rb1 and rb2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
RadioGroup group = findViewById(R.id.group);
group.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener(){
@Override
public void onCheckedChanged(RadioGroup gp, int checkedId){
RadioButton rb1 = findViewById(R.id.rb1);
RadioButton rb2 = findViewById(R.id.rb2);

if(rb1.isChecked()){
//Do something
}
if(rb2.isChecked()){
//Do something
}
}
});

Views - ListViews

  • ListViews are views that enable you to display a long list of items in a vertically
    scrolling list
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class MainActivity extends ListActivity{
String[] area = {"Tsim Sha Tsui", "Hung Hom", "Yau Ma Tei", "Mongkok"};

@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
//no need to use activity_main
//setContentView(R.layout.activity_main);

//make use of ArrayAdapter
setListAdapter(new ArrayAdapt<String>(this, android.R.layout.simple_list_item_1, area));
}

//onListItemClick() is fired whenever an item in the ListView has been clicked
@Override
protected void onListItemClick(ListView l, View v, int position, long id){
super.onListItemClick(l,v,position,id);
//Display the area selected using the Toast class
Toast.makeText(this, "The area you selected is " + area[position], Toast.LENGTH_SHORT).show();
}
}

Note:

  • in this example, the MainActivity class extends the ListActivity class
    • ListActivity class extends the Activity class and displays a list of items by binding to a data source
  • There is no need to modify the activity_main.xml file to include the ListView because the ListActivity class itself contains a ListView
  • setListAdapter() method to programmatically fill the entire screen of the activity with a ListView
  • The ArrayAdapter object manages the array of strings that are displayed by the ListView

Views - Some other Views

ImageView - a view that shows images on the device screen

  • You may add an image to your project under the res/mipmap folder
    • Or use the default ic_launcher images

GridView - shows items in a two-dimensional scrolling grid

  • You can use the GridView together with an ImageView to display a series of images

Implement the ImageAdapter class and then bind it to the GridView

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

GridView gridView = findViewById(R.id.myGridView);
gridView.setAdapter(new ImageAdapter(this));

gridView.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
public void onItemClick(AdapterView parent, View v, int position, long id)
{
//When an image is selected,
//display a Toast message indicating the selected image
Toast.makeText(getBaseContext(),
"pic" + (position+1) + " selected",
Toast.LENGTH_SHORT).show();
}
});
}

You can also specify how images are spaced in the GridView by setting the padding for each image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
public View getView(int position, View convertView, ViewGroup parent){
ImageView imageView;
if(convertView == null){
imageView = new ImageView(context);
imageView.setLayoutParams(new GridView.LayoutParams(150, 150));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(5,5,5,5);
} else{
imageView = (ImageView) convertView;
}
imageView.setImageResource(imageIDs[position]);
return imageView;
}

Action Bar - the traditional title bar located at the top of the deivce’s screen

  • the Action Bar displays the application icon and the activity title
  • Optionally, on the right side of the Action Bar are action items

In basic activity, The Action Bar is already set up.

To hide the Action Bar:

1
2
//Hide this in the onCreate method:
//setSupportActionBar(toolbar);

Besides displaying the application icon and the activity title on the left of the Action Bar, you can also display additional items on the Action Bar.

  • These additional items are called action items
  • Action items are shortcuts to some of the commonly performed operations in your application

To create menu items:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Override
public boolean onCreateOptionsMenu(Menu menu){
//Inflate the menu; this adds items to the action bar if it is present.
//getMenuInflater().inflate(R.menu.menu_main, menu);
CreateMenu(menu);
return true;
}

private void CreateMenu(Menu menu){
//menu.add(groupId, itemId, order, title);
MenuItem mnu1 = menu.add(0,0,0,"Item 1");{
mnu1.setIcon(R.mipmap.ic_launcher);
mnu1.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
}
MenuItem mnu2 = menu.add(0,1,1,"Item 2");{
mnu2.setIcon(R.mipmap.ic_launcher);
mnu2.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
}
MenuItem mnu3 = menu.add(0,2,2,"Item 3");{
mnu3.setIcon(R.mipmap.ic_launcher);
mnu3.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
}
MenuItem mnu4 = menu.add(0,3,3,"Item 4");{
mnu4.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
}
MenuItem mnu5 = menu.add(0,4,4,"Item 5");{
mnu5.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
}
}

When a menu item is selected by the user, the onOptionsItemSelected() method is called

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
public boolean onOptionsItemSelected(MenuItem item){
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.cml.
//int id = item.getItemId();

//noinspection SimplifiabbleIfStatement
//if(id == R.id.action_settings){
// return true;
//}

return MenuChoice(item);
}

Self-defined MenuChoice() method to check which menu item was clicked and then display a message:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private boolean MenuChoice(MenuItem item){
switch (item.getItemId()){
case 0:
//do something
return true;
case 1:
//do something
return true;
case 2:
//do something
return true;
case 3:
//do something
return true;
case 4:
//do something
return true;
}
return false;
}

TimePicker - enables users to select a time of the day, in either 24-hour mode or AM/PM mode

  • Choose an SDK that is level 23 or greater

Example:

DatePicker - enable users to select a particular date on the activity

  • Noted that TimePicker is using a spinner

ViewGroups - Layouts

The purpose of a ViewGroup is to group views logically, such as a group of buttons with a similar purpose

  • A Layout is used to group and arrange views visually on the screen

Now all the Layouts are inside the ConstraintLayout.

FrameLayout

  • All widgets are pinned to top left corner by default
  • used to help you control the stacking of single views as the screen is resized

LinearLayout

  • arranges views in a single column or a single row
    • for horizontal rows of views – LinearLayout (Horizontal)
    • for vertical columns of views – LinearLayout (Vertical)
  • Child views can be arranged either horizontally or vertically

TableLayout

  • groups views into rows and columns
  • Each row can contain one or more views
    • Each view placed within a row to form a cell
  • The width of each column is determined by the largest width of each cell in that column

RelativeLayout

  • enables programmer to specify how child views are positioned relative to each other
  • Notice that each view embedded within the RelativeLayout has attributes that enable it to align with another view. These attributes are as follows:
    • layout_alignParentTop
      • Aligns the view to the top of the parent view
    • layout_alignParentStart
      • Aligns the view to the left of the parent view
    • layout_alignStart
    • layout_alignEnd
    • layout_below
    • layout_centerHorizontal

ScrollView

A ScrollView is a special type of FrameLayout.

  • enables users to scroll through a list of views that occupy more space than the physical display.
  • The ScrollView can contain only one child view or ViewGroup, which normally is a LinearLayout.

It can be scrolled down when there are so many components.

Units of Measurement

  • dp - density-independent pixel
    • 1 dp is equivalent to one pixel on a 160 dpi (dots per inch) screen
    • The 160 dpi screen is the baseline density assumed by Android
  • sp - scale-independent pixel
    • This is similar to dp and is recommended for specifying font sizes.
    • it is also scaled by the user’s font size preference
  • pt - point
    • A point is defined to be 1/72 of an inch, based on the physical screen size
  • px - pixel
    • Corresponds to actual pixels on the screen. Using this unit is not recommended.
    • px = dp * screen dpi /160
  • match_parent
    • The height/width of border will match the parent content.
  • wrap_content
    • The height/width of border will fit and only wrap the content.

Display Orientation

  • Android supports two screen orientations: portrait and landscape

  • By default, when you change the display orientation of your Android device, the current activity automatically redraws its content in the new orientation

  • This is because the onCreate() method of the activity is fired whenever there is a change in display orientation.

  • When the views are redrawn, they may be drawn in their original locations (depending on the layout selected)

Two techniques to handle changes in screen orientation:

  • Anchoring
    • The easiest way is to “anchor” your views to the four edges of the screen
    • When the screen orientation changes, the views can anchor neatly to the edges
  • Resizing and repositioning
    • Whereas anchoring and centralizing are simple techniques to ensure that views can handle changes in screen orientation, the ultimate technique is resizing each and every view according to the current screen orientation

Anchoring Views

Anchoring can be easily achieved by using RelativeLayout

Example:

  • Consider the following main.xml file, which contains five Button views embedded within the element

Common attributes for RelativeLayout:

  • layout_alignParentStart
    • Aligns the view to the left of the parent view
  • layout_alignParentEnd
    • Aligns the view to the right of the parent view
  • layout_alignParentTop
    • Aligns the view to the top of the parent view
  • layout_alignParentBottom
    • Aligns the view to the bottom of the parent view
  • layout_centerVertical
    • Centers the view vertically within its parent view
  • layout_centerHorizontal
    • Centers the view horizontally within its parent view

Managing Changes to Screen Orientation

When we change the Orientation, we basically start the app all over again.

  • Changing screen orientation destroys an activity and re-creates it
  • When an activity is re-created, its current state might be lost

onPause() -> onStop() -> onDestroy() -> onCreate -> onStart() -> onResume()

When an activity is killed, it fires one or both of the following methods:

  • onPause()
    • This method is always fired whenever an activity is killed or pushed into the background
  • onSaveInstanceState()
    • This method is also fired whenever an activity is about to be killed or put into the background (just like the onPause() method)
    • The onSaveInstanceState() method is not fired when an activity is being unloaded from the stack (such as when the user pressed the back button) because there is no need to restore its state later

Persisting State Information

To preserve the state of an activity, you could always implement the onPause() method and then use your own ways to preserve the state of your activity.

Such as:

  • Using a database
  • internal
  • External file storage

If you simply want to preserve the state of an activity so that it can be restored later when the activity is re-created (such as when the device changes orientation), a much simpler way is to implement the onSaveInstanceState() method, as it provides a Bundle object as an argument so that you can use it to save your activity’s state

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public void onSaveInstanceState(Bundle outState){
//---save whatever you need to persist---
outState.putString("msg" , "hi!");
super.onSaveInstanceState(outState);
}

@Override
public void onRestoreInstanceState(Bundle savedInstanceState){
super.onRestoreInstanceState(savedInstanceState);
//---retrieve the information persisted earlier---
String msg = savedInstanceState.getString("msg");
}

Detecting Orientation Changes

Sometimes you need to know the device’s current orientation during runtime

  • use getResources()
1
2
3
4
5
6
7
8
9
10
11
12
//They can be putted in onCreate() method
if(getResources().getConfiguration().orientation ==
Configuration.ORIENTATION_LANDSCAPE){
//Do something...
Log.d("StateInfo", "Landscape");
}
else if(getResources().getConfiguration().orientation ==
Configuration.ORIENTATION_PORTRAIT){
//Do something...
Log.d("StateInfo", "Portrait");
}

Controlling the Orientation

To ensure that the application is displayed in only a certain orientation:

  • For example, many games are displayed only in landscape mode
  • We need to Programmatically force a change in orientation using the setRequestedOrientation() method
1
2
3
4
5
6
7
8
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

//---change to lanscape mode---
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}

Besides using the setRequestOrientation() method, you can also use the android:screenOrientation attribute on the <activity> element in AndroidManifest.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity"
android:screenOrientation="landscape"> <!--set orientation-->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

Extra

Toast

https://www.javatpoint.com/android-toast-example

1
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();

Dialog

https://developer.android.com/guide/topics/ui/dialogs

https://www.tutorialspoint.com/android/android_alert_dialoges.htm