Tutorial details

Creating custom and compound Views in Android - Tutorial | App Code for Sale | Preview

Creating custom and compound Views in Android - Tutorial | Android Tutorial

Creating custom and compound Views in Android

Overview PAGE TOP

Lars Vogel

Version 2.8

Copyright © 2009, 2010, 2011, 2012, 2013 Lars Vogel

07.01.2013

vogellafan.5.1.jpg

Creating custom Views in Android

This tutorials describes how to create custom Views with Android. It is based on Eclipse 4.2, Java 1.6 and Android 4.0.4 (Ice Cream Sandwich).

1.1. Defining own Views PAGE TOP

You can also create you own Views by either extending existing Views classes or by extending View directly.

Views draw themself in the onDraw() method. You get a Canvas object which allows to perform drawing operations on it, e.g. draw lines, circle, text and Bitmaps.

1.2. Using Custom Views in layout files PAGE TOP

Custom Views can be used in layout files. For this you need to use the full qualified name in the layout file, e.g. using the package and class name.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button" />

    <de.vogella.android.ownview.MyDrawView
        android:id="@+id/myDrawView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout> 

1.3. Create Images of Views PAGE TOP

Every View class support the creating of an image of its current display. The following coding shows an example for that.

# Build the Drawing Cache
view.buildDrawingCache();

# Create Bitmap
Bitmap cache = view.getDrawingCache();

# Save Bitmap
saveBitmap(cache);
view.destroyDrawingCache(); 

2. Define additional attributes for your custom Views PAGE TOP

You can also define additional attributes for your compound or custom View. To define additional attributes create an attrs.xml file in your res/xml folder. The following shows an example.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="Options">
        <attr name="titleText" format="string" localization="suggested" />
        <attr name="valueColor" format="color" />
    </declare-styleable>

</resources> 

To use these attributes in your layout file you have to declare them in the XML header.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
<!-- define new name space for your attributes -->
    xmlns:custom="http://schemas.android.com/apk/res/com.vogella.android.view.compoundview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
>
<!-- Assume that this is your new component. It uses your new attributes -->
        <com.vogella.android.view.compoundview.ColorOptionsView
            android:layout_width="match_parent"
            android:layout_height="?android:attr/listPreferredItemHeight"
            custom:titleText="Background color"
            custom:valueColor="@android:color/holo_green_light"
             />

</LinearLayout> 

The following example shows how you components can access these attributes.

package com.vogella.android.view.compoundview;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

public class ColorOptionsView extends View {

  private View mValue;
  private ImageView mImage;

  public ColorOptionsView(Context context, AttributeSet attrs) {
    super(context, attrs);

    TypedArray a = context.obtainStyledAttributes(attrs,
        R.styleable.Options, 0, 0);
    String titleText = a.getString(R.styleable.Options_titleText);
    int valueColor = a.getColor(R.styleable.Options_valueColor,
        android.R.color.holo_blue_light);
    a.recycle();

    // More stuff
  }


}

3. Compound Views PAGE TOP

Compound Views (also known as Compound Components) are pre-configured ViewGroups which can be used as one unit. For such a control you define a layout with View components and pre-define the View interaction.

You would define a layout file and extend the corresponding ViewGroup class. In this class you inflate the layout file and implement the View connection logic

4.1. Create project PAGE TOP

Create a new Android project called com.vogella.android.customview.compoundview with an activity called MainActivity.

4.2. Define and use additional attributes PAGE TOP

Create the following attributes file called attrs.xml in your res/xml folder.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="Options">
        <attr name="titleText" format="string" localization="suggested" />
        <attr name="valueColor" format="color" />
    </declare-styleable>

</resources> 

Change the layout file for the Activity to the following.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:custom="http://schemas.android.com/apk/res/com.vogella.android.view.compoundview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:showDividers="middle"
    android:divider="?android:attr/listDivider"
    tools:context=".MainActivity" >

        <com.vogella.android.view.compoundview.ColorOptionsView
            android:id="@+id/view1"
            android:layout_width="match_parent"
            android:layout_height="?android:attr/listPreferredItemHeight"
            android:background="?android:selectableItemBackground"
            android:onClick="onClicked"
            custom:titleText="Background color"
            custom:valueColor="@android:color/holo_green_light"
             />

        <com.vogella.android.view.compoundview.ColorOptionsView
            android:id="@+id/view2"
            android:layout_width="match_parent"
            android:layout_height="?android:attr/listPreferredItemHeight"
            android:background="?android:selectableItemBackground"
            android:onClick="onClicked"
            custom:titleText="Foreground color"
            custom:valueColor="@android:color/holo_orange_dark"
             />

</LinearLayout> 

4.3. Create compound view PAGE TOP

Create the following layout file called viewcoloroptions.xml for your compound view.

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android" >

    <TextView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:layout_centerVertical="true"
      android:layout_marginLeft="16dp"
        android:textSize="18sp" 
        />

  <View
      android:layout_width="26dp"
      android:layout_height="26dp"
      android:layout_centerVertical="true"
      android:layout_marginLeft="16dp"
      android:layout_marginRight="16dp"
      />

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
      android:layout_marginRight="16dp"
        android:layout_centerVertical="true" 
        android:visibility="gone"
        />

</merge> 

Create the following compound view.

package com.vogella.android.customview.compoundview;

import com.vogella.android.view.compoundview.R;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

public class ColorOptionsView extends LinearLayout {

  private View mValue;
  private ImageView mImage;

  public ColorOptionsView(Context context, AttributeSet attrs) {
    super(context, attrs);

    TypedArray a = context.obtainStyledAttributes(attrs,
        R.styleable.ColorOptionsView, 0, 0);
    String titleText = a.getString(R.styleable.ColorOptionsView_titleText);
    int valueColor = a.getColor(R.styleable.ColorOptionsView_valueColor,
        android.R.color.holo_blue_light);
    a.recycle();

    setOrientation(LinearLayout.HORIZONTAL);
    setGravity(Gravity.CENTER_VERTICAL);

    LayoutInflater inflater = (LayoutInflater) context
        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    inflater.inflate(R.layout.view_color_options, this, true);

    TextView title = (TextView) getChildAt(0);
    title.setText(titleText);

    mValue = getChildAt(1);
    mValue.setBackgroundColor(valueColor);

    mImage = (ImageView) getChildAt(2);
  }

  public ColorOptionsView(Context context) {
    this(context, null);
  }

  public void setValueColor(int color) {
    mValue.setBackgroundColor(color);
  }

  public void setImageVisible(boolean visible) {
    mImage.setVisibility(visible ? View.VISIBLE : View.GONE);
  }

} 

4.4. Create Activity PAGE TOP

Change your activity to the following code and run your application.

package com.vogella.android.customview.compoundview;

import com.vogella.android.view.compoundview.R;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends Activity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.activity_main, menu);
    return true;
  }

  public void onClicked(View view) {
    String text = view.getId() == R.id.view1 ? "Background" : "Foreground";
    Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
  }

} 

The running application should look like the following screenshot.

vogellafan.5.2.png

5. Creating custom views PAGE TOP

By extending the View class or one of its subclasses you can create your own Views.

To draw your Views you typically use the 2D Canvas API.

6.1. Overview PAGE TOP

The Canvas API allows to create complex graphical effects.

You paint on a Bitmap surface. The Canvas class provides the drawing methods to draw on a bitmap and the Paint class specifies how you draw on the bitmap.

6.2. The Canvas class PAGE TOP

The Canvas object contains the bitmap on which you draw. It also provides methods for drawing operations, e.g. drawARGB() for drawing a color, drawBitmap() to draw a Bitmap, drawText() to draw a text, drawRoundRect() to draw a rectangle with rounded corners and much more.

6.3. The Paint class PAGE TOP

For drawing on the Canvas object you use an object of type Paint.

The Paint class allows to specify the color, font and certain effects for the drawing operation.

The setStyle() method allows to specify if the only the outline (Paint.Style.STROKE), the filled part (Paint.Style.FILL) or both (Paint.Style.STROKEANDFILL)should be drawn.

You can set the alpha channel of the Paint via the setAlpha() method.

Via Shaders you can define that the Paint is filled with more than one color.

6.4. Shader PAGE TOP

A shader allows to define for a Paint object the content which should be drawn. For example you can use a BitmapShader to define that a bitmap should be used to draw. This allows you for example to draw an image with rounded corners. Simply define a BitmapShader for your Paint object and use the drawRoundRect() method to draw a rectancle with rounded corners.

Other Shaders provided by the Android platform are LinearGradient, RadialGradient and SweepGradient for drawing color gradients.

To use a Shaders assign it to your Paint object via the setShader() method.

If the area which is filled is larger than the Shaders you can define via the Shader tile mode how the rest should be filled. The Shader.TileMode.CLAMP constant defines that the edge corners should be used to fill the extra space, the Shader.TileMode.MIRROR constant defines that the image is mirrored and Shader.TileMode.REPEAT defines that the image will be repeated.

7. Persisting View data PAGE TOP

Most standard Views can restore there state during a configuration change. Android will search based on the ID of the view in the layout for the view and pass a Bundle to the view which the view can use to restore its state.

Reference PAGE TOP

http://www.vogella.com/articles/AndroidCustomViews/article.html

0 Comments Leave a comment

Please login in order to leave a comment.

Newest first
!

Sign-in to your Chupamobile Account.

The Easiest way to Launch your next App or Game.

Join Chupamobile and get instant access to thousands of ready made App and Game Templates.

Creating an account means you’re okay with Chupamobile’s Terms of Service and Privacy Policy.