Download Android User Interfaces (UIs)

Document related concepts
no text concepts found
Transcript
Android User Interfaces (UIs)
Akhilesh Tyagi
User Interface
• UI refers to everything that goes on the blank screen to interact with the user.
• Control buttons – touch creates an event.
• editText – fields allow user to enter some text to be used by the app (user sign‐in).
• Commonly referred to as controls and widgets.
Recall: Android widgets
Analog/DigitalClock
Button
Checkbox
Date/TimePicker
EditText
Gallery
ImageView/Button
ProgressBar
RadioButton
Spinner
TextView
MapView, WebView
Marty Stepp, Stanford, CS193A
View
• A View is an object that draws something on the screen that the user can interact with.
• A ViewGroup is an object that holds other View (and ViewGroup) objects in order to define the layout of the interface.
View
• View is a geometric (rectangular) area on screen.
• It responds to events
0,0
X-axis
10
Y-axis
20
Height=15
Width=50
<?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:orientation="vertical" >
<TextView android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="I am a TextView" />
<Button android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="I am a Button" />
</LinearLayout>
I am a TextView
I am a Button
UI XML elements
• The name of an XML element for a view corresponds to the Android class it represents
• a <TextView> element creates a TextView widget in your UI
• a <LinearLayout> element creates a LinearLayout view group.
• When you load a layout resource in your app, Android initializes each node of the layout into a runtime object you can use to define additional behaviors, query the object state, or modify the layout.
Layout Declaration
1) Declare UI elements in XML. Android provides a straightforward XML vocabulary that corresponds to the View classes and subclasses, such as those for widgets and layouts.
2) Instantiate layout elements at runtime. Your application can create View and ViewGroup objects (and manipulate their properties) programmatically.
UI in XML
• The advantage to declaring your UI in XML is that it enables you to better separate the presentation of your application from the code that controls its behavior
• Your UI descriptions are external to your application code, which means that you can modify or adapt it without having to modify your source code and recompile.
• you can create XML layouts for different screen orientations, different device screen sizes, and different languages.
<?xml version="1.0" encoding="utf‐8"?>
<LinearLayout
xmlns:android="http://schemas.android.co
m/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent
" android:orientation="vertical" >
<TextView android:id="@+id/text"
android:layout_width="wrap_cont
ent"
android:layout_height="wrap_cont
ent"
android:text="Hello, I am a TextView" />
<Button android:id="@+id/button"
android:layout_width="wrap_conte
nt"
android:layout_height="wrap_conte
nt"
android:text="Hello, I am a Button" />
</LinearLayout>
• Each layout file
must contain exactly
one root element,
which must be a
View or ViewGroup
object.
• Vertical linear layout
• TextView and
Button as views
Loading the XML Layout file
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
}
XML Layout Attributes
• ID ‐ Any View object may have an integer ID associated with it
• When the application is compiled, this ID is referenced as an integer, but the ID is typically assigned in the layout XML file as a string
• android:id="@+id/my_button“
• The at‐symbol (@) at the beginning of the string indicates that the XML parser should parse and expand the rest of the ID string and identify it as an ID resource.
• The plus‐symbol (+) means that this is a new resource name that must be created and added to our resources (in the R.java file)
Use of ID
• <Button android:id="@+id/my_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/my_button_text"/
>
• Button myButton = (Button) findViewById(R.id.my_button);
• Defining IDs for view objects is important when creating a RelativeLayout. In a relative layout, sibling views can define their layout relative to another sibling view, which is referenced by the unique ID.
• android:layout_below="@id/myTextView"
• An ID need not be unique throughout the entire tree, but it should be unique within the part of the tree you are searching
Android Resources ID
• android:id="@android:id/empty“
• With the android package namespace in place, we're now referencing an ID from the android.R resources class, rather than the local resources class.
Programmatically created views
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView myTextView = new TextView(this);
setContentView(myTextView);
myTextView.setText(“Hello, Android”);
}
Standard Views
• TextView A standard read only text label. • EditText An editable text entry box. • ListView A View Group that creates and manages a group of Views used to display the items in a List. The standard ListView displays the string value of an array of objects using Text
• Spinner Composite control that displays a TextView and an associated ListView that lets you select an item from a list to display in the textbox. It’s made from a Text View displaying the current selection, combined with a button that displays a selection dialog when pressed.
• Button Standard push‐
button
• CheckBox Two‐state button represented with a checked or unchecked box
• Radio Button Two‐state grouped buttons. Presents the user with a number of binary options of which only one can be selected at a time.
Button with text and image:
Basic button:
<Button
<Button
android:layout_width
android:layout_width="wrap_content"
android:layout_height="wrap_content ="wrap_content"
android:layout_heigh
"
t="wrap_content"
android:text="@string/button_text"
android:text="@strin
... />
g/button_text"
android:drawableLeft
="@drawable/button_icon"
... />
Button with personalized image:
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/button_icon"
... />
Button (link)
A clickable widget with a text label
●
key attributes:
set to false to disable the button
android:clickable="bool"
unique ID for use in Java code
android:id="@+id/theID"
android:onClick="function" function to call in activity when clicked android:text="text"
●
(must be public, void, and take a View
arg)
text to put in the button
represented by Button class in Java code
Button b = (Button) findViewById(R.id.theID);
...
Marty Stepp, Stanford, CS193A
ImageButton
A clickable widget with an image label
●
key attributes:
android:clickable="bool"
android:id="@+id/theID"
android:onClick="function"
android:src="@drawable/img"
●
set to false to disable the button
unique ID for use in Java code
function to call in activity when clicked (must be public, void, and take a View arg)
image to put in the button
(must correspond to an image resource)
to set up an image resource:
–
–
put image file in project folder app/src/main/res/drawable
use @drawable/foo to refer to foo.png
●
use simple file names with only letters and numbers
Marty Stepp, Stanford, CS193A
ImageView
Displays an image without being clickable
●
●
key attributes:
android:id="@+id/theID"
unique ID for use in Java code
android:src="@drawable/img"
image to put in the screen
(must correspond to an image resource)
to change the visible image, in Java code:
–
–
get the ImageView using findViewById
call its setImageResource method and pass R.drawable.filename
Marty Stepp, Stanford, CS193A
EditText (link)
An editable text input box
●
key attributes:
android:hint="text"
android:id="@+id/theID"
android:inputType="type"
gray text to show before user starts to type
unique ID for use in Java code
android:lines="int"
android:maxLines="int"
android:text="text"
android:textSize="size"
number of visible lines (rows) of input
max lines to allow user to type in the box
initial text to put in box (default empty)
size of font to use (e.g. "20dp")
–
what kind of input is being typed;
number,phone,date,time,...
others: capitalize, digits, fontFamily, letterSpacing, lineSpacingExtra, minLines, numeric, password, phoneNumber, singleLine, textAllCaps, textColor, typeface
Marty Stepp, Stanford, CS193A
CheckBox (link)
An individual toggleable on/off switch
●
key attributes:
android:checked="bool"
set to true to make it initially checked
set to false to disable the checkbox
android:clickable="bool"
unique ID for use in Java code
android:id="@+id/theID"
android:onClick="function" function to call in activity when clicked android:text="text"
●
In Java code:
(must be public, void, and take a View
arg)
text to put next to the checkbox
CheckBox cb = (CheckBox) findViewById(R.id.theID); cb.toggle();
cb.setChecked(true); cb.performClick();
Marty Stepp, Stanford, CS193A
RadioButton (link)
A toggleable on/off switch; part of a group
●
key attributes:
android:checked="bool"
android:clickable="bool"
android:id="@+id/theID"
android:onClick="function"
android:text="text"
●
set to true to make it initially checked
set to false to disable the button
unique ID for use in Java code
function to call in activity when clicked (must be public, void, and take a View
arg)
text to put next to the button
need to be nested inside a RadioGroup tag in XML so that only one can be selected at a time
Marty Stepp, Stanford, CS193A
RadioGroup example
<LinearLayout ...
android:orientation="vertical" android:gravity="center|top">
<RadioGroup ...
android:orientation="horizontal">
<RadioButton ... android:id="@+id/lions"
android:text="Lions"
android:onClick="radioClick" />
<RadioButton ... android:id="@+id/tigers"
android:text="Tigers"
android:checked="true"
android:onClick="radioClick" />
<RadioButton ... android:id="@+id/bears"
android:text="Bears, oh my!"
android:onClick="radioClick" />
</RadioGroup>
</LinearLayout>
Marty Stepp, Stanford, CS193A
Spinner (link)
A drop‐down menu of selectable choices
●
●
key attributes:
android:clickable="bool"
android:id="@+id/theID"
android:entries="@array/array"
set to false to disable the spinner
android:prompt="@string/text"
title text when dialog of choices pops up
unique ID for use in Java code
set of options to appear in spinner (must match an array in strings.xml)
also need to handle events in Java code (see later)
–
–
must get the Spinner object using findViewById
then call its setOnItemSelectedListener method (see example)
Marty Stepp, Stanford, CS193A
Responding to Click Events
• When the user clicks a button, the Button object receives an on‐click event.
• To define the click event handler for a button, add the android:onClick attribute to the <Button> element in your XML layout. The value for this attribute must be the name of the method you want to call in response to a click event. The Activity hosting the layout must then implement the corresponding method.
<?xml version="1.0" encoding="utf‐8"?>
<Button xmlns:android="http://schemas.android.com/a
pk/res/android"
android:id="@+id/button_send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button_send"
android:onClick="sendMessage" />
Button onClick
• Within the Activity that hosts this layout, the following method handles the click event:
• /** Called when the user touches the
button */
public void sendMessage(View view) {
// Do something in response to button
click
}
Associate onClick Listener in Program
• might be necessary if you instantiate the Button at runtime
• To declare the event handler programmatically, create an View.OnClickListener object and assign it to the button by calling setOnClickListener(View.OnClickListener)
• Button button = (Button) findViewById(R.id.button_send);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Do something in response to button click
}
});
Anonymous Inner Classes‐ onClickListener
class Account { private int mBalance; public Account() { mBalance = 0; } public void deposit(int amt) {mBalance = mBalance + amt; }
// A basic example of an Anonymous Inner Class. public void innerDemo() { final int temp = mBalance / 10; Runnable runnable = // This is an "anonymous inner class" ‐‐ 3 parts new Runnable() { // 1. The superclass public void run() { // 2. method(s) inside the AIC // 3. Code inside the method ‐‐ typically this is the part you care // about. System.out.println("run() is running"); deposit(temp); // Can call methods on the outer object } };
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // Store a pointer to editText1. Set up button1 to add a !. editText1 = (EditText) findViewById(R.id.editText1); Button button = (Button) findViewById(R.id.button1); button.setOnClickListener( // Create a OnClickListener AIC new OnClickListener() { public void onClick(View v) { editText1.setText(editText1.getText() + "!"); } } ); ...
Input Events
• In Android, there's more than one way to intercept the events from a user's interaction with your application. Capture the events from the specific View object that the user interacts with. The View class provides the means to do so.
• View class contains a collection of nested interfaces with callbacks. These interfaces, called event listeners, are your ticket to capturing the user interaction with your UI.
Event Listeners
• An event listener is an interface in View class that contains a single callback method
• These methods will be called by the Android framework when the View to which the listener has been registered is triggered by user interaction with the item in the UI.
• Included in the event listener interfaces are the callback methods in following slide.
• onClick(): From View.OnClickListener. This is called when the user either touches the item (when in touch mode), or focuses upon the item with the navigation‐keys or trackball and presses the suitable "enter" key or presses down on the trackball.
• onLongClick(): From View.OnLongClickListener. This is called when the user either touches and holds the item (when in touch mode), or focuses upon the item with the navigation‐keys or trackball and presses and holds the suitable "enter" key or presses and holds down on the trackball (for one second).
• onFocusChange(): From View.OnFocusChangeListener. This is called when the user navigates onto or away from the item, using the navigation‐keys or trackball.
• onKey(): From View.OnKeyListener. This is called when the user is focused on the item and presses or releases a hardware key on the device.
• onTouch(): From View.OnTouchListener. This is called when the user performs an action qualified as a touch event, including a press, a release, or any movement gesture on the screen (within the bounds of the item).
Callback Method Return Value
• onClick() callback has no return value.
• onLongClick() ‐ This returns a boolean to indicate whether you have consumed the event and it should not be carried further. That is, return true to indicate that you have handled the event and it should stop here; return false if you have not handled it and/or the event should continue to any other on‐click listeners.
• onKey() ‐ returns a boolean
• onTouch() ‐ returns a boolean. This event can have multiple actions that follow each other. If you return false when the down action event is received, you indicate that you have not consumed the event and are also not interested in subsequent actions from this event. Thus, you will not be called for any other actions within the event, such as a finger gesture, or the eventual up action event. Event Handler Registration
• These callback event handler methods are the sole inhabitants of their respective interface
• pass an instance of your implementation to the respective View.set...Listener() method
• hardware key events are always delivered to the View currently in focus
• dispatched starting from the top of the View hierarchy, and then down, until they reach the appropriate destination
Reusing onClick handler
// in MainActivity.java
public class MainActivity extends Activity {
public void radioClick(View view) {
// check which radio button was clicked if (view.getId() == R.id.lions) {
// ...
} else if (view.getId() == R.id.tigers) {
// ...
} else {
// bears ...
}
}
Marty Stepp, Stanford, CS193A
Motion Event
• Event is an object with many attributes.
• Motion Event extends Input Event class.
• Each touch generates multiple motion events.
• int ACTION_DOWN ‐ A pressed gesture has started, the motion contains the initial starting location.
• ACTION_UP; ACTION_MOVE; ACTION_CANCEL
• getX(int), getY(int); • getHistoricalX(int, int), getHistoricalY(int, int)
Consuming all samples for all pointers in a motion event in time order
void printSamples(MotionEvent ev) {
final int historySize = ev.getHistorySize();
final int pointerCount = ev.getPointerCount();
for (int h = 0; h < historySize; h++) {
System.out.printf("At time %d:", ev.getHistoricalEventTime(h));
for (int p = 0; p < pointerCount; p++) {
System.out.printf(" pointer %d: (%f,%f)",
ev.getPointerId(p), ev.getHistoricalX(p, h), ev.getHistoricalY(p, h));
}
}
System.out.printf("At time %d:", ev.getEventTime());
for (int p = 0; p < pointerCount; p++) {
System.out.printf(" pointer %d: (%f,%f)",
ev.getPointerId(p), ev.getX(p), ev.getY(p));
}
}
Motion Event
• http://developer.android.com/reference/andr
oid/view/MotionEvent.html
String resources
●
Declare constant strings and arrays in res/values/strings.xml:
<resources>
<string name="name">value</string>
<string name="name">value</string>
<string‐array name="arrayname">
<item>value</item>
<item>value</item>
<item>value</item>
<!‐‐ must escape ' as \' in values ‐‐>
...
<item>value</item>
</string‐array>
</resources>
●
Refer to them in Java code:
– as a resource:
R.string.name, R.array.name
– as a string or array: getResources().getString(R.string.name), getResources().getStringArray(R.array.name)
Marty Stepp, Stanford, CS193A
<Spinner
android:id="@+id/planets_spinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
To populate the spinner with a list of choices, you then need to specify a SpinnerAdapter in your Activity
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="planets_array">
<item>Mercury</item>
<item>Venus</item>
<item>Earth</item>
<item>Mars</item>
<item>Jupiter</item>
<item>Saturn</item>
<item>Uranus</item>
<item>Neptune</item>
</string-array>
</resources>
Spinner Adapter
Spinner spinner = (Spinner) findViewById(R.id.spinner);
// Create an ArrayAdapter using the string array and a default spinner layout
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,
R.array.planets_array, android.R.layout.simple_spinner_item);
// Specify the layout to use when the list of choices appears
adapter.setDropDownViewResource(android.R.layout.simple_s
pinner_dropdown_item);
// Apply the adapter to the spinner
spinner.setAdapter(adapter);
Another Spinner example
<LinearLayout ...>
<Spinner ... android:id="@+id/tmnt" android:entries="@array/turtles" android:prompt="@string/choose_turtle" />
<TextView ... android:id="@+id/result" />
</LinearLayout>
●
in res/values/strings.xml:
<resources>
<string name="choose_turtle">Choose a turtle:</string>
<string‐array name="turtles">
<item>Leonardo</item>
<item>Michelangelo</item>
<item>Donatello</item>
<item>Raphael</item>
</string‐array>
</resources>
Marty Stepp, Stanford, CS193A
Spinner event example
// in MainActivity.java
public class MainActivity extends Activity {
...
@Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
Spinner spin = (Spinner) findViewById(R.id.tmnt);
spin.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> spin, View v, int i, long id) { TextView result = (TextView) findViewById(R.id.turtle_result); result.setText("You chose " + spin.getSelectedItem());
}
public void onNothingSelected(AdapterView<?> parent) {}
});
}
}
Marty Stepp, Stanford, CS193A
// empty
ScrollView
A container with scrollbars around another widget or container
<LinearLayout ...>
...
<ScrollView
android:layout_width="wrap_content" android:layout_height="wrap_content">
<TextView ... android:id="@+id/turtle_info" />
</ScrollView>
</LinearLayout>
Marty Stepp, Stanford, CS193A
Checkbox
<?xml version="1.0" encoding="utf‐8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<CheckBox android:id="@+id/checkbox_meat"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/meat"
android:onClick="onCheckboxClicked"/>
<CheckBox android:id="@+id/checkbox_cheese"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cheese"
android:onClick="onCheckboxClicked"/>
</LinearLayout>
Sizing and Positioning
How does the programmer specify where each component appears, how big each component should be, etc.?
●
Absolute positioning (C++, C#, others):
–
–
●
Programmer specifies exact pixel coordinates of every component.
"Put this button at (x=15, y=75) and make it 70x31 px in size."
Layout managers (Java, Android):
–
Objects that decide where to position each component based on some
general rules or criteria.
●
–
"Put these four buttons into a 2x2 grid and put these text boxes in a horizontal flow in the south part of the app."
More flexible and general; works better with a variety of devices.
Marty Stepp, Stanford, CS193A
ViewGroup as layout
●
ViewGroup superclass represents containers of widgets/views
–
–
–
●
layouts are described in XML and mirrored in Java code
Android provides several pre‐existing layout managers; you can define your own custom layouts if needed
layouts can be nested to achieve combinations of features
in the Java code and XML:
–
–
–
an Activity is a ViewGroup
various Layout classes are also ViewGroups
widgets can be added to a ViewGroup, which will then manage that widget's position/size behavior
Marty Stepp, Stanford, CS193A
XML, in brief
●
XML : a language for describing hierarchical text data. *
–
–
Uses tags that consist of elements and attributes. Tags can be nested.
Some tags are opened and closed; others self‐close.
<element attr="value" attr="value"> ... </element>
(self‐closing)
<element attr="value" attr="value" />
●
Example:
* XML is case‐sensitive!
<!‐‐ this is a comment ‐‐>
<course name="CPRE 388" semester="Fall 15">
<instructor>Akhilesh Tyagi</instructor>
<ta>Jane Smith</ta>
</course>
Marty Stepp, Stanford, CS193A
Changing layouts
• go to the Text view for your layout XML file
• modify the opening/closing tags to the new layout
type,
• e.g. LinearLayout
• now go back to Design view and add widgets
Marty Stepp, Stanford, CS193A
LAYOUTS
LinearLayout (link)
●
●
●
lays out widgets/views in a single line
orientation of horizontal (default) or vertical items do not wrap if they reach edge of screen!
horizontal
vertical
Marty Stepp, Stanford, CS193A
LinearLayout example 1
<LinearLayout ...
android:orientation="horizontal" tools:context=".MainActivity">
<Button ... android:text="Button 1" />
<Button ... android:text="Button 2 Hooray" />
<Button ... android:text="Button 3" />
<Button ... android:text="Button 4
Very Long Text" />
</LinearLayout>
●
In our examples, we'll use ... when omitting boilerplate code that is auto‐generated by
Android Studio and not relevant to the specific
example at hand.
Marty Stepp, Stanford, CS193A
LinearLayout example 2
<LinearLayout ...
android:orientation="vertical" tools:context=".MainActivity">
<Button ... android:text="Button 1"
<Button ... android:text="Button 2
Hooray"
<Button ... android:text="Button 3"
<Button ... android:text="Button 4
Very Long
Text"
</LinearLayout>
Marty Stepp, Stanford, CS193A
/>
/>
/>
/>
Layout Parameters
• layout_width and layout_height ‐ each view is required to define them
• wrap_content tells your view to size itself to the dimensions required by its content
• fill_parent (renamed match_parent in API Level 8) tells your view to become as big as its parent view group will allow
• optional margins and borders
Sizing an individual widget
●
width and height of a widget can be:
–
–
–
wrap_content : exactly large enough to fit the widget's content
match_parent : as wide or tall as 100% of the screen or layout
a specific fixed width such as 64dp (not usually recommended)
●
dp = device pixels; dip = device‐independent pixels; sp = scaling pixels
<Button ...
android:layout_width="match_parent" android:layout_height="wrap_content" />
Marty Stepp, Stanford, CS193A
Layout/View parameters
• A view has a location, expressed as a pair of left and top coordinates, and two dimensions, expressed as a width and a height
• Dynamically determine location by invoking getLeft() and getTop() on a view. These methods both return the location of the view relative to its parent
• convenience methods ‐ getRight()
and getBottom(). getRight() = getLeft() + getWidth()
Layout/View Parameters
• A view actually possesses two pairs of width and height values.
• measured width and measured height define how big a view wants to be within its parent. The measured dimensions can be obtained by calling getMeasuredWidth() and getMeasuredHeight()
• width and height, or sometimes drawing width and drawing height. getWidth() and getHeight()
• To measure its dimensions, a view takes into account its padding. The padding is expressed in pixels for the left, top, right and bottom parts of the view.
• set using the setPadding(int, int, int, int) method and queried by calling getPaddingLeft(), getPaddingTop(), getPaddin
gRight() and getPaddingBottom()
• Even though a view can define a padding, it does not provide any support for margins
Widget box model
• content: every widget or view has a certain size (width x height) for its content, the widget itself
• padding: you can artificially increase the widget's size by
applying padding in the widget just outside its content
• border: outside the padding, a line around edge of widget
• margin: separation from neighboring widgets on screen
Marty Stepp, Stanford, CS193A
Padding
●
padding: extra space inside widget
– set padding to adjust all sides; paddingTop, Bottom, Left, Right for one side
– usually set to specific values like 10dp
(some widgets have a default value ~16dp)
<LinearLayout ...
android:orientation="vertical">
<Button ... android:text="Button 1"
android:padding="50dp" />
<Button ... android:text="Button 2 Hooray" />
<Button ... android:text="Button 3"
android:paddingLeft="30dp" android:paddingBottom="40dp" />
</LinearLayout>
Marty Stepp, Stanford, CS193A
Margin
●
margin: extra space outside widget to separate it from others
– set layout_margin to adjust all sides; layout_marginTop, Bottom, Left, Right
– usually set to specific values like 10dp
(set defaults in res/values/dimens.xml)
<LinearLayout ...
android:orientation="vertical">
<Button ... android:text="Button 1"
android:layout_margin="50dp" />
<Button ... android:text="Button 2 Hooray" />
<Button ... android:text="Button 3"
android:layout_marginLeft="30dp"
android:layout_marginTop="40dp" />
</LinearLayout>
Marty Stepp, Stanford, CS193A
Layouts
Linear layout: A
layout that organizes
its children into a
single horizontal or
vertical row. It creates
a scrollbar if the length
of the window
exceeds the length of
the screen.
Relative layout:
Enables you to
specify the location
of child objects
relative to each
other (child A to the
left of child B) or to
the parent (aligned
to the top of the
parent)
Web view layout:
Displays web pages
Linear Layout
• LinearLayout is a view group that aligns all children in a single direction, vertically or horizontally. You can specify the layout direction with android:orientation attribute.
• assign a weight to individual children with the android:layout_weight attribute.
• This attribute assigns an "importance" value to a view in terms of how much space is should occupy on the screen.
• Default weight is zero.
• if there are three text fields and two of them declare a weight of 1, while the other is given no weight, the third text field without weight will not grow and will only occupy the area required by its content. The other two will expand equally to fill the remaining space
• If the third field is then given a weight of 2 (instead of 0), then it gets half the total remaining space, while the first two share the rest equally.
Weight
●
weight: gives elements relative sizes by integers
–
–
widget with weight K gets K/total fraction of total size
cooking analogy: "2 parts flour, 1 part water, ..."
<LinearLayout ...
android:orientation="vertical">
<Button ... android:text="B1"
android:layout_weight="1" />
<Button ... android:text="B2"
android:layout_weight="3" />
<Button ... android:text="B3"
android:layout_weight="1" />
</LinearLayout>
Marty Stepp, Stanford, CS193A
<?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:paddingLeft="16dp"
android:paddingRight="16dp"
android:orientation="vertical" >
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="@string/to" />
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="@string/subject" />
<EditText
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="top"
android:hint="@string/message" />
<Button
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="@string/send" />
</LinearLayout>
Linear Layout parameters
• android:layout_gravity
• top: Push object to the top of its container, not changing its size
• bottom, left, right, center_vertical (Place object in the vertical center of its container), fill_vertical, center_horizontal, fill_horizontal, center, fill, start, end
• Must be one or more (separated by '|')
Gravity
●
gravity: alignment direction that widgets are pulled
– top, bottom, left, right, center
– combine multiple with |
– set gravity on the layout to adjust all widgets; set layout_gravity on an individual widget
Marty Stepp, Stanford, CS193A
<LinearLayout ...
android:orientation="vertical" android:gravity="center|right">
<Button ... android:text="Button 1" />
<Button ... android:text="Button 2 Hooray" />
<Button ... android:text="Button 3" />
<Button ... android:text="Button 4 Very Long Text" />
<Button ... android:text="Button 5"
android:layout_gravity="left" />
</LinearLayout>
Marty Stepp, Stanford, CS193A
Nested layout
●
to produce more complicated appearance, use a nested layout
–
●
(layouts inside layouts)
what layout(s) are used to create
the appearance at right?
–
–
overall activity:
internal layouts:
Marty Stepp, Stanford, CS193A
Nested layout template
<OuterLayoutType ...>
<InnerLayoutType ...>
<Widget ... />
<Widget ... />
</InnerLayoutType>
<InnerLayoutType ...>
<Widget ... />
<Widget ... />
</InnerLayoutType>
<Widget ... />
<Widget ... />
</OuterLayoutType>
Marty Stepp, Stanford, CS193A
Nested layout exercise
●
Write the layout XML necessary to create the following app UI.
–
–
–
How many overall layouts are needed?
Which widgets go into which layouts?
...
Marty Stepp, Stanford, CS193A
Nested layout solution
<LinearLayout ...
android:orientation="vertical" android:gravity="center|top">
<Button ... android:text="B1" />
<LinearLayout ...
android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"
android:gravity="center|top">
<Button ... android:text="B2" />
<Button ... android:text="Button Number
/>
3"
<Button ... android:text="B4" />
</LinearLayout>
<Button ... android:text="B5" />
<Button ... android:text="B6" android:layout_gravity="left" />
<LinearLayout ...
android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center|top">
<Button ... android:text="B7" />
<Button ... android:text="Button Number 8" />
</LinearLayout>
Marty Stepp, Stanford, CS193A
</LinearLayout>
Relative Layout
• view group that displays child views in relative positions.
• child views specify their position relative to the parent view or to each other (specified by ID)
• align two elements by right border, or make one below another, centered in the screen, centered left, and so on.
• By default, all child views are drawn at the top‐left of the layout,
Relative Layout Properties
• android:layout_alignParentTop: If "true", makes the top edge of this view match the top edge of parent.
• android:layout_centerVertical: If "true", centers this child vertically within its parent.
• android:layout_below: Positions the top edge of this view below the view specified with a resource ID.
• android:layout_toRightOf: Positions the left edge of this view to the right of the view specified with a resource ID.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingLeft="16dp"
android:paddingRight="16dp" >
<EditText
android:id="@+id/name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="@string/reminder" />
<Spinner
android:id="@+id/dates"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_below="@id/name"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="@+id/times" />
<Spinner
android:id="@id/times"
android:layout_width="96dp"
android:layout_height="wrap_content"
android:layout_below="@id/name"
android:layout_alignParentRight="true" />
<Button
android:layout_width="96dp"
android:layout_height="wrap_content"
android:layout_below="@id/times"
android:layout_alignParentRight="true"
android:text="@string/done" />
</RelativeLayout>
Relative Layout Parameters
android:layout_above, android:layout_alignBaseline, android:layout_alignBottom, android:layout_alignEnd, android:layout_alignLeft, android:layout_alignParentBottom, android:layout_alignParentEnd, android:layout_alignParentLeft, android:layout_alignParentRight, android:layout_alignParentStart, android:layout_alignParentTop, android:layout_alignRight,
android:layout_alignStart, android:layout_alignTop, android:layout_below, android:layout_centerHorizontal
Building Layouts with an Adapter
• When the content for your layout is dynamic or not pre‐
determined, you can use a layout that subclasses AdapterView to populate the layout with views at runtime
• A subclass of the AdapterView class uses an Adapter to bind data to its layout. The Adapter behaves as a middle‐man between the data source and the AdapterView layout
• the Adapter retrieves the data (from a source such as an array or a database query) and converts each entry into a view that can be added into the AdapterView layout
Adapter Views
List view:
Displays a scrolling
single column list.
Grid view:
Displays a scrolling grid
of columns and rows.
GridLayout
●
lays out widgets/views in lines of rows and columns
–
–
●
orientation attribute defines row‐major or column‐major order
introduced in Android 4; replaces older TableLayout
by default, rows and columns are equal in size
–
each widget is placed into "next" available row/column index unless it is given an explicit layout_row and layout_column attribute
–
grid of 4 rows, 3 columns:
Marty Stepp, Stanford, CS193A
GridLayout example 1
<GridLayout ...
android:rowCount="2" android:columnCount="3" tools:context=".MainActivity">
<Button ... android:text="Button 1" />
<Button ... android:text="Button Two" />
<Button ... android:text="Button 3" />
<Button ... android:text="Button Four" />
<Button ... android:text="Button 5" />
<Button ... android:text="Button Six" />
</GridLayout>
Marty Stepp, Stanford, CS193A
GridLayout example 2
<GridLayout ...
android:rowCount="2" android:columnCount="3" android:orientation="vertical">
<Button ... android:text="Button 1" />
<Button ... android:text="Button Two" />
<Button ... android:text="Button 3" />
<Button ... android:text="Button Four" />
<Button ... android:text="Button 5"
android:layout_row="1" android:layout_column="2" />
<Button ... android:text="Button Six"
android:layout_row="0" android:layout_column="2" />
</RelativeLayout>
Marty Stepp, Stanford, CS193A
GridLayout example 3
<GridLayout ...
android:rowCount="2" android:columnCount="3">
<Button ... android:text="B1" />
<Button ... android:text="B2" />
<Button ... android:text="Button Number 3!" />
<Button ... android:text="B4"
android:layout_columnSpan="2" android:layout_gravity="center" />
<Button ... android:text="Button #5" />
<Button ... android:text="B6" android:layout_paddingTop="40dp" android:layout_paddingBottom="40dp" />
<Button ... android:text="B7" />
<Button ... android:text="Button #8"
android:layout_gravity="right" />
</RelativeLayout>
Marty Stepp, Stanford, CS193A
Array Adapter
• Data source is an array
ArrayAdapter adapter = new
ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1,
myStringArray);
• Constructor arguments are: app Context; The layout that contains a TextView for each string in the array; The string array
• Then simply call setAdapter() on your ListView:
ListView listView = (ListView)
findViewById(R.id.listview);
listView.setAdapter(adapter);
simple_list_item_1
<TextView
xmlns:android="http://schemas.android.com/apk/res/
android"
android:id="@android:id/text1"
style="?android:attr/listItemFirstLineStyle"
android:paddingTop="2dp"
android:paddingBottom="3dp"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
Example App – ToDoList
• Create a new project
• The activity UI will be a vertical linear layout with EditText view and ListView view.
Layout Resource main.xml
<?xml version="1.0" encoding="UTF‐8"?>
<LinearLayout android:layout_height="match_parent" android:layout_width="match_parent" android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android"> <EditText android:layout_height="wrap_content" android:layout_width="match_parent" android:contentDescription="@string/addItemContentDescription" android:hint="@string/addItemHint" android:id="@+id/myEditText"/>
<ListView android:layout_height="wrap_content" android:layout_width="match_parent" android:id="@+id/myListView"/></LinearLayout>
String resources
<?xml version="1.0" encoding="UTF‐8"?>
<resources>
<string name="app_name">ToDoList</string>
<string name="addItemHint">New To Do Item </string>
<string name="addItemContentDescription">New To Do Item
</string></resources>
onCreate Method
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Inflate your View
setContentView(R.layout.main);
// Get references to UI widgets
ListView myListView = (ListView) findViewById(R.id.myListView);
final EditText myEditText = (EditText) findViewById(R.id.myEditText);
onCreate method contd.
// Create the Array List of to do items
final ArrayList<String> todoItems = new ArrayList<String>();
// Create the Array Adapter to bind the array to the List View
final ArrayAdapter<String> aa;
aa = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1,
todoItems);
// Bind the Array Adapter to the List View
myListView.setAdapter(aa);
onCreate method contd.
myEditText.setOnKeyListener(new View.OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN)
if ((keyCode == KeyEvent.KEYCODE_DPAD_CENTER) ||
(keyCode == KeyEvent.KEYCODE_ENTER)) {
todoItems.add(0, myEditText.getText().toString());
aa.notifyDataSetChanged();
Listen to D-pad
myEditText.setText("");
Center button or
return true;
Enter key press
}
return false;
}
}); }}
ToDoList App
• Does not save to‐do items (do not persist)
• Can’t edit or remove an item
• Other useful attributes such as due date/target time, priorities are missing
Multiple events per view
• Same view can handle multiple events arising from the same touch.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/myLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button android:id="@+id/myButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
<TextView android:id="@+id/myTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/myButton" />
</RelativeLayout>
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_event_example); Button button = (Button)findViewById(R.id.myButton); button.setOnClickListener
( new Button.OnClickListener() { public void onClick(View v) { TextView myTextView = (TextView)findViewById (R.id.myTextView); myTextView.setText("Button clicked"); } } ); }
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_event_example); Button button = (Button)findViewById(R.id.myButton); button.setOnClickListener( new Button.OnClickListener() { public void onClick(View v) { TextView myTextView = (TextView)findViewById(R.id.myTextView); myTextView.setText("Button clicked"); } } ); button.setOnLongClickListener( new Button.OnLongClickListener() { public boolean
onLongClick(View v) { TextView myTextView = (TextView)findViewById(R.id.myTextView); myTextView.setText("Long button click"); return true; } } ); }
• What if onLongClick returns false?
button.setOnLongClickListener( new Button.OnLongClickListener() { public boolean
onLongClick(View v) { TextView myTextView = (TextView)findViewById(R.id.myTextView); myTextView.setText("Long button click"); return false; } } );
Both onLongClick and onClick are called.
Touch and Multitouch events
• Slightly more complicated than click events
• MotionEvent object is passed.
• Multiple touch events forming a gesture sequence could be generated.
myLayout.setOnTouchListener( new RelativeLayout.OnTouchListener()
{ public boolean
onTouch(View v, MotionEvent m)
{ // Perform tasks here
return true; } } );
Touch Actions
• When the first touch on a view occurs, the MotionEvent object will contain an action type of ACTION_DOWN together with the coordinates of the touch.
• When that touch is lifted from the screen, an ACTION_UP event is generated.
• Any motion of the touch between the ACTION_DOWN and ACTION_UP events will be represented by ACTION_MOVE events.
Pointers
• When more than one touch is performed simultaneously on a view, the touches are referred to as pointers.
• In a multi‐touch scenario, pointers begin and end with event actions of type ACTION_POINTER_UP, ACTION_POINTER_DOWN
• In order to identify the index of the pointer that triggered the event, the getActionIndex() callback method of the MotionEvent object must be called.
Pointers • Each pointer is referenced by an index value and assigned an ID.
• The current number of pointers can be obtained via a call to the getPointerCount() method of the current MotionEvent object.
• The ID for a pointer at a particular index in the list of current pointers may be obtained via a call to the MotionEvent getPointerId() method.
Getting pointer at index 0
public boolean onTouch
(View v, MotionEvent m) { int pointerCount = m.getPointerCount(); int pointerId = m.getPointerId(0); return true; }
• Relative layout with two text views textView1, textView2
public class MotionEventActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_motion_event); RelativeLayout myLayout = (RelativeLayout)findViewById(R.id.RelativeLayout1); myLayout.setOnTouchListener( new RelativeLayout.OnTouchListener() { public boolean
onTouch(View v, MotionEvent m) { handleTouch(m); return true; }
} ); } . . . }
void handleTouch(MotionEvent m) { TextView textView1 = (TextView)findViewById(R.id.textView1); TextView textView2 = (TextView)findViewById(R.id.textView2); int pointerCount = m.getPointerCount(); for (int i = 0; i < pointerCount; i++) { int x = (int) m.getX(i); int y = (int) m.getY(i); int id = m.getPointerId(i); int action = m.getActionMasked(); int actionIndex = m.getActionIndex(); String actionString; switch (action) { case MotionEvent.ACTION_DOWN: actionString = "DOWN"; break; case MotionEvent.ACTION_UP: actionString = "UP"; break; case MotionEvent.ACTION_POINTER_DOWN: actionString = "PNTR DOWN"; break; case MotionEvent.ACTION_POINTER_UP: actionString = "PNTR UP"; break; case MotionEvent.ACTION_MOVE: actionString = "MOVE"; break; default: actionString = ""; } String touchStatus = "Action: " + actionString + " Index: " + actionIndex
+ " ID: " + id + " X: " + x + " Y: " + y; if (id == 0) textView1.setText(touchStatus); else textView2.setText(touchStatus); } }
Event Propagation
ACTION_DOWN Event
• Assume View C does not have a onTouchListener() registered.
• DOWN event is passed to onTouchEvent() method of View C. It returns false.
• The event is then passed to Viewgroup B’s onTouchEvent() method. Returns false as well.
• Same with Viewgroup A.
• Future events (for this gesture) do not get delivered to any of them (A, B, C) since they all said false.
ACTION_DOWN Event (C cares)
• Assume View C does have a onTouchListener() registered, onTouchEvent().
• DOWN event is passed to onTouchEvent() method of View C. It handles it and then returns true.
• Because View C indicates that it is handling the event, Viewgroups A and B do not get it.
• Future events (for this gesture) go to C since it flags that it is handling the first DOWN event. Event Intercept
• Let us say you are scrolling in a ScrollView. You touch (ACTION_DOWN) in View C?
• Who should handle it?
• Probably top‐level ViewGroup ScrollView.
EventIntercept
• MOVE event is passed to onInterceptTouchEvent() of ViewGroup A. returns false.
• onInterceptTouchevent() of Scrollview
ViewGroup B notices that user moved finger beyond a threshold (slop), and hence intercepts it by returning true.
• Modified CANCEL event is then passed to View C.
Exceptions
• requestDisallowInterceptTouchEvent() could be overridden by View C
• Extend your own ViewGroup class and redefine dispatchEvent() method to do whatever you want to do with these events.