Custom Components

Custom Components

Android Offers a sophisticated and powerful componentized model for building our UI, based on the fundamental layout classes: View and ViewGroup. To start with, the platform includes a variety of prebuilt View and ViewGroup subclasses --- called widgets and layouts, respectively --- that we can use to construct our UI.

If none of the prebuilt widgets or layouts meets our needs, we can create our own View subclass. If we only need to make small adjustments to an existing widget or layout, we can simply subclass the widget or layout and override its methods.

Creating our own View subclasses gives us precise control over the appearance and function of a screen element. To give an idea of the control we get with custom views, here are some examples of what we could do with them:

a> We could create a completely custom-rendered View type.

b> We could combine a group of View components into a new single component.

c> We could override the way that an EditText component is rendered on the screen.

d> We could capture other events like key presses and handle them in some custom way.

The Basic Approach

Here is a high level overview of what we need to know to get started in creating our own View components:

a> Extend an existing View class or subclass with our own class.

b> Override some of the methods from the superclass. The superclass methods to overrides start with "on". 

c> Use our new extension class. 

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 we want to create a new public View for wider use in our application).

Fully Customized Components

Fully customized components can be used to create graphical components that appear however we wish. We want something that the built-in components just won't do, no matter how we combine them.

Fortunately, we can easily create components that look and behave in any way we like, limited perhaps only by our imagination, the size of the screen, and the available processing power (remember that ultimately our application might have to run on something with significantly less power than our desktop workstation).

To Create a fully customized component:

a> The most generic view we can extend is, unsurprisingly, View, so we will usually start by extending this to create our new super component.

b> We can supply a constructor which can take attributes and parameters from the XML, and we can also consume our own such attributes and parameters.

c> We will probably want to create our own event listeners, property accessors and modifiers, and possibly more sophisticated behavior in our component class as well.

d> We will almost certainly want to override onMeasure() and are also likely to need to override onDraw() if we 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 100 x 100 --- which is probably not what we want.

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

Extend onDraw() and onMeasure()

The onDraw() method delivers we a Canvas upon which we can implement anything we want: 2D graphics, other standard or custom components, styled text, or anything else we can think of.

However, this does not apply to 3D graphics. If we want to use 3D graphics, we must extend SurfaceView instead of View, and draw from a separate thread.

onMeasure() is a little more involved. onMeasure() is a critical piece of the rendering contract between our component and its container. 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 we fail to call this method from an overridden onMeasure() method, the result will be an exception at measurement time.

At a high level, implementing onMeasure() looks something like this:

1> 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 we should produce. 

2> Our 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).

3> 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.

Compound Controls

If we don't want to create a completely customized component, but instead are looking to put together a reusable component that consists of a group of existing controls, then creating a Compound Component (or Compound Control) might fit the bill. In a nutshell, this bring together a number of more atomic controls (or views) into a logical group of items that can be treated as a single thing.

To create a compound component:

a> The usual starting point is a Layout of some kind, so create a class that extends a Layout. Remember that other layouts can be nested inside, so the compound component can be arbitrarily complex and structured. Note that just like with an Activity, we can use either the declarative (XML-based) approach to creating the container components, or we can nest them programmatically from our code.

b> In the constructor for the new class, take whatever parameters the superclass expects, and pass them through to the superclass constructor first. Note that we also might introduce our own attributes and parameters into the XML that can be pulled out and used by our constructor.

c> We can also create listeners for events that our contained views might generate.

d> We might also create our own properties with accessors and modifiers.

e> In the case of extending a Layout, we don't need to override the onDraw() and onMeasure() methods since the layout will have default behavior that will likely work just fine. However, we can still override them if we need to.

f> We might override other on... methods.

To summarize, the use of a Layout as the basic for a Custom Control has a number of advantages, including:

1> We can specify the layout using the declarative XML files just like with an activity screen, or we can create views programmatically and nest them into the layout from our code.

2> The onDraw() and onMeasure() methods (plus most of the other on... methods) will likely have suitable behavior so we don't have to override them.

3> In the end, we can very quickly construct arbitrarily complex compound views and re-use them as if they were a single component.

Modifying an Existing View Type

There is an even easier option for creating a custom View which is useful in certain circumstances. If there is a component that is already very similar to what we want, we can simply extend that component and just override the behavior that we want to change. We can do all of the things we would do with a fully customized component, but by starting with a more specialized class in the View hierarchy, we can also get a lot of behavior for free that probably does exactly what we want.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值