Custom components

35
Mohammad Nazmul Hossain [email protected] Custom Components

Transcript of Custom components

Page 1: Custom components

Mohammad Nazmul Hossain

[email protected]

Custom Components

Page 3: Custom components

1.1 Introduction

Android offers a robust componentized model for building your UI.

It is based on the fundamental layout classes:

View

ViewGroup

The platform includes a variety of prebuilt View and ViewGroup subclasses. They are:

Widgets

Layouts

Page 4: Custom components

1.1 Introduction (Contd.)

A partial list of available widgets are:

Button

TextView

EditText

ListView

CheckBox

RadioButton

Gallery

Spinner

The more special-purpose widgets are:

AutoCompleteTextView

ImageSwitcher

TextSwitcher

Page 5: Custom components

1.2 Why Custom Components? (Not default!)

If none of the prebuilt widgets or layouts meets your needs, you can create your own

View subclass.

This approach above gives you the full control over your widgets.

If you only need to make small adjustments to an existing widget or layout, you can

simply subclass the widget or layout and override its methods.

This approach above concerns with minor changes suitable with your requirements. Thus

it is often easier.

Page 6: Custom components

1.3 Some Application Scenarios

You could create a completely custom-rendered View type, for example a "volume

control" knob rendered using 2D graphics, and which resembles an analog electronic

control.

You could combine a group of View components into a new single component, perhaps

to make something like a ComboBox (a combination of popup list and free entry text

field), a dual-pane selector control (a left and right pane with a list in each where you

can re-assign which item is in which list), and so on.

You could override the way that an EditText component is rendered on the screen with

some special features. Such as having lines like notepad.

You could capture other events like key presses and handle them in some custom way

(such as for a game).

Page 7: Custom components

1.4 The Basic Approach

Extend an existing View class or subclass with your own class.

Override some of the methods from the superclass. The superclass methods to override

start with 'on', for example, onDraw(), onMeasure(), and onKeyDown(). This is similar

to the 'on…' events in Activity or ListActivity that you override for lifecycle and

other functionality hooks.

Use your new extension class. Once completed, your new extension class can be used in

place of the view upon which it was based.

Page 8: Custom components

Important Tips !

Extension classes can be defined as inner classes inside the

activities that use them. This is useful because it controls access

to them but isn't necessary (perhaps you want to create a

new public View for wider use in your application).

Page 9: Custom components

1.5 Fully Customized Components

Fully customized components can be used to create graphical components that appear

however you wish.

To create a fully customized component:

The most generic view you can extend View, so you will usually start by extending this to

create your new super component.

You can supply a constructor which can take attributes and parameters from the XML, and you

can also consume your own such attributes and parameters (perhaps the color and range of the

VU meter, or the width and damping of the needle, etc.)

You will probably want to create your own event listeners, property accessors and

modifiers, and possibly more sophisticated behavior in your component class as well.

You will almost certainly want to override onMeasure() and are also likely to need to

override onDraw() if you want the component to show something. While both have default

behavior, the default onDraw() will do nothing, and the default onMeasure() will always set a

size of 100x100 — which is probably not what you want.

Other on... methods may also be overridden as required.

Page 10: Custom components

1.5.1 Extend onDraw() and onMeasure()

The onDraw() method delivers you a Canvas upon which you can implement anything

you want: 2D graphics, other standard or custom components, styled text, or anything

else you can think of.

This does not apply to 3D graphics. If you want to use 3D graphics, you must

extend SurfaceView instead of View, and draw from a separate thread. (An

important fact!)

Page 11: Custom components

1.5.1 Extend onDraw() and onMeasure() (Contd.)

onMeasure() should be overridden to efficiently and accurately report the

measurements of its contained parts.

This is made slightly more complex by the requirements of limits from the parent

(which are passed in to the onMeasure() method) and by the requirement to call the

setMeasuredDimension() method with the measured width and height once they have

been calculated.

If you fail to call this method from an overridden onMeasure() method, the result will

be an exception at measurement time.

The detail of onMeasure() method is given in the next slide.

Page 12: Custom components

1.5.1 Extend onDraw() and onMeasure() (Contd.)

The overridden onMeasure() method is called with width and height measure

specifications (widthMeasureSpec and heightMeasureSpec parameters, both are

integer codes representing dimensions) which should be treated as requirements for the

restrictions on the width and height measurements you should produce.

Your component's onMeasure() method should calculate a measurement width and

height which will be required to render the component. It should try to stay within the

specifications passed in, although it can choose to exceed them (in this case, the parent

can choose what to do, including clipping, scrolling, throwing an exception, or asking

the onMeasure() to try again, perhaps with different measurement specifications).

Once the width and height are calculated, the setMeasuredDimension(int width, int

height) method must be called with the calculated measurements. Failure to do this will

result in an exception being thrown.

Page 13: Custom components

1.6 Framework Summary

Category Methods Description

Creation Constructors There is a form of the constructor

that are called when the view is

created from code and a form that is

called when the view is inflated from

a layout file. The second form should

parse and apply any attributes

defined in the layout file.

onFinishInflate() Called after a view and all of its

children has been inflated from

XML.

Layout onMeasure(int, int) Called to determine the size

requirements for this view and all of

its children.

onLayout(boolean, int, int, int, int) Called when this view should assign

a size and position to all of its

children.

onSizeChanged(int, int, int, int) Called when the size of this view has

changed.

Page 14: Custom components

1.6 Framework Summary (Contd.)

Category Methods Description

Drawing onDraw(Canvas) Called when the view should

render its content.

Event processing onKeyDown(int, KeyEvent) Called when a new key event

occurs.

onKeyUp(int, KeyEvent) Called when a key up event occurs.

onTrackballEvent(MotionEvent) Called when a trackball motion

event occurs.

onTouchEvent(MotionEvent) Called when a touch screen motion

event occurs.

Focus onFocusChanged(boolean, int,

Rect)

Called when the view gains or loses

focus.

onWindowFocusChanged(boolean) Called when the window containing

the view gains or loses focus.

Attaching onAttachedToWindow() Called when the view is attached to

a window.

onDetachedFromWindow() Called when the view is detached

from its window.

onWindowVisibilityChanged(int) Called when the visibility of the

window containing the view has

changed.

Page 15: Custom components

1.7 Modifying an Existing View Type

In this section, adding some features in a EditText will be discussed.

To accomplish this, we need to do the things described below.

The Definition

Class Initialization

Overridden Methods

Use the Custom Component

These steps will be described in the following slides.

Page 16: Custom components

1.7.1 The Definition

The class is defined with the following line:

public class NumberView extends EditText implements OnClickListener,

OnLongClickListener, OnTouchListener

It extends EditText, which is the View we have chosen to customize in this case. When

we are finished, the new class will be able to substitute for a normal EditText view.

As we going to implement OnClickListener, OnLongClickListener,

OnTouchListener, we will be able to override some existing methods to fulfill our

purposes.

In this example we are going to override onTouch() method.

The main purpose of overriding this method is to provide an custom EditText, in

which when user touches, no default keyboard will pop out.

Another important purpose is to provide a user facility to move cursor position

proper with user’s touch event.

Page 17: Custom components

1.7.2 Class Initialization

As always, the super is called first. Furthermore, this is not a default constructor, but a

parameterized one.

The EditText is created with these parameters when it is inflated from an XML layout

file, thus, our constructor needs to both take them and pass them to the superclass

constructor as well.

Our implemented code segment is given below.

public NumberView(Context context, AttributeSet attrs, int defStyle)

{

super(context, attrs, defStyle);

setListeners();

c = context;

}

Page 18: Custom components

1.7.2 Class Initialization (Contd.)

public NumberView(Context context, AttributeSet attrs) {

super(context, attrs);

setListeners();

c = context;

}

public NumberView(Context context) {

super(context);

setListeners();

// TODO Auto-generated constructor stub

}

Page 19: Custom components

1.7.3 Overridden Methods

Here we are only describing the overriding of onTouch method.

@Override

public boolean onTouch(View v, MotionEvent event) {

Layout layout = getLayout();

float x = event.getX() + getScrollX();

float y = event.getY() + getScrollY();

int line = layout.getLineForVertical((int) y);

int offset = layout.getOffsetForHorizontal( line, x);

setSelection(offset); //moving the cursor position on user touch

hideSoftKey();

return true;

}

Page 20: Custom components

1.7.3 Overridden Methods (Contd.)

Here is the implementation of hideSoftKey() method.

private void hideSoftKey() {

InputMethodManager imm = (InputMethodManager)

c.getSystemService(Context.INPUT_METHOD_SERVICE);

imm.hideSoftInputFromWindow(getWindowToken(), 0);

}

Page 21: Custom components

Question-Answer

Question: What is the difference between returning true and false

in the overridden onTouch() method?

Answer: Return true if the listener has consumed the event, false

otherwise.

To be more specific, Returning true means that other views that also

having a touchlistener will not get this event for handling. If you

return false the event will be passed to parent views for handling.

21

Page 22: Custom components

1.7.4 Use the Custom Component

We can add our custom EditText in the layout file that can be found under res/layout

folder. The code segment is given below.

<view

class="com.example.androidcustomview.NumberView"

android:id="@+id/yourGivenID"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:padding="10dip"

android:scrollbars="vertical"

android:fadingEdge="vertical" />

Page 23: Custom components

1.7.4 Use the Custom Component (Contd.)

Page 25: Custom components

2.1 Creating a View Class

A well-designed custom view is much like any other well-designed class. It encapsulates a

specific set of functionality with an easy to use interface, it uses CPU and memory

efficiently, and so forth. In addition to being a well-designed class, though, a custom view

should:

Conform to Android standards

Provide custom styleable attributes that work with Android XML layouts

Send accessibility events

Be compatible with multiple Android platforms.

Page 26: Custom components

2.1.1 Subclass a View

All of the view classes defined in the Android framework extend View

Your custom view can also extend View directly, or you can save time by extending one of the existing view subclasses, such as Button.

To allow the Android Developer Tools to interact with your view, you must provide a constructor that takes a Context and an AttributeSet object as parameters.

This constructor allows the layout editor to create and edit an instance of your view.

class PieChart extendsView {public PieChart(Context context, AttributeSet attrs) {

super(context, attrs);}

}

Page 27: Custom components

2.1.2 Define Custom Attributes

To add a built-in View to your user interface, you specify it in an XML element and

control its appearance and behavior with element attributes.

Well-written custom views can also be added and styled via XML.

To enable this behavior in your custom view, you must:

Define custom attributes for your view in a <declare-styleable> resource element

Specify values for the attributes in your XML layout

Retrieve attribute values at runtime

Apply the retrieved attribute values to your view

In this section you will be able to learn how to define custom attributes and specify their

values.

Page 28: Custom components

2.1.2 Define Custom Attributes (Contd.)

To define custom attributes, add <declare-styleable> resources to your project. It is

customary to put these resources into a res/values/attrs.xml file. Here is an example

of an attrs.xml file:

<resources>

<declare-styleable name="PieChart">

<attr name="showText" format="boolean"/>

<attr name="labelPosition" format="enum">

<enum name="left" value="0"/>

<enum name="right" value="1"/>

</attr>

</declare-styleable>

</resources>

This code declares two custom attributes, showText and labelPosition, that belong to a

styleable entity named PieChart.

The name of the styleable entity is, by convention, the same name as the name of the

class that defines the custom view. (An important fact!)

Page 29: Custom components

2.1.2 Define Custom Attributes (Contd.)

Once you define the custom attributes, you can use them in layout XML files just like

built-in attributes.

The only difference is that your custom attributes belong to a different namespace.

Instead of belonging to the http://schemas.android.com/apk/res/android namespace,

they belong to http://schemas.android.com/apk/res/[your package name].

For example, here's how to use the attributes defined for PieChart:

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

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

xmlns:custom="http://schemas.android.com/apk/res/com.example.customviews">

<com.example.customviews.charting.PieChart

custom:showText="true"

custom:labelPosition="left" />

</LinearLayout>

Page 30: Custom components

2.1.3 Apply Custom Attributes

When a view is created from an XML layout, all of the attributes in the XML tag are read

from the resource bundle and passed into the view's constructor as an AttributeSet.

Although it's possible to read values from the AttributeSet directly, doing so has some

disadvantages:

Resource references within attribute values are not resolved

Styles are not applied

Instead, pass the AttributeSet to obtainStyledAttributes(). This method passes back

a TypedArray array of values that have already been dereferenced and styled.

The Android resource compiler does a lot of work for you to make

calling obtainStyledAttributes() easier. For each <declare-styleable> resource in the res

directory, the generated R.java defines both an array of attribute ids and a set of

constants that define the index for each attribute in the array. You use the predefined

constants to read the attributes from the TypedArray.

Page 31: Custom components

2.1.3 Apply Custom Attributes (Contd.)

Here is how the PieChart class reads its attributes:

public PieChart(Context context, AttributeSet attrs) {

super(context, attrs);

TypedArray a = context.getTheme().obtainStyledAttributes(attrs,R.styleable.PieChart,0, 0);

try {

mShowText = a.getBoolean(R.styleable.PieChart_showText, false);

mTextPos = a.getInteger(R.styleable.PieChart_labelPosition, 0);

}

finally {

a.recycle();

}

}

Note that TypedArray objects are a shared resource and must be recycled after

use.(An important fact!)

Page 32: Custom components

2.1.4 Add Properties and Events

Attributes can only be read when the view is initialized.

To provide dynamic behavior, expose a property getter and setter pair for each custom

attribute.

The following snippet shows how PieChart exposes a property called showText:

public boolean isShowText() {

return mShowText;

}

public void setShowText(boolean showText) {

mShowText = showText;

invalidate();

requestLayout();

}

Calling to the methods invalidate() and requestLayout() are crucial to ensure that the view behaves

reliably. (Why? Please see the next slide!)

Page 33: Custom components

2.1.4 Add Properties and Events (Contd.)

You have to invalidate the view after any change to its properties that might

change its appearance, so that the system knows that it needs to be redrawn.

Likewise, you need to request a new layout if a property changes that might affect

the size or shape of the view.

Forgetting these method calls can cause hard-to-find bugs.

Page 35: Custom components

Thank You.