custom components
TRANSCRIPT
1. Custom Components
Source: http://developer.android.com/guide/topics/ui/custom-components.html
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
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
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.
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).
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.
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).
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.
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!)
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.
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.
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.
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.
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.
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.
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;
}
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
}
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;
}
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);
}
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
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" />
1.7.4 Use the Custom Component (Contd.)
2. Creating Custom Views
Source: http://developer.android.com/training/custom-views/index.html
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.
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);}
}
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.
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!)
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>
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.
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!)
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!)
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.
Related Topics
For further read, please visit the following links given below.
Custom Drawing
Source: http://developer.android.com/training/custom-views/custom-drawing.html
Making the View Interactive
Source: http://developer.android.com/training/custom-views/making-interactive.html
Optimizing the View
Source: http://developer.android.com/training/custom-views/optimizing-view.html
Thank You.