Copy this link when reproducing:
http://www.casperlee.com/en/y/blog/203
To create a user-defined widget in Android application, there are 2 ways at least:
1. Extends a known widget and enriches its functions.
2. Extends the View class and creates the widget by drawing it totally.
For the TabHeaderView widget, I'll use the first method.
To create the TabHeaderView widget, it involves the following steps:
- create the layout file for the widget
- create a class which extends the LinearLayout class
- enrich the functions
Here are the detailed steps:
1. Add a new layout file named "widget_tab_header_view_layout.xml" in the folder "app -> res -> layout", and put the following text in:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/MainLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<ToggleButton
android:id="@+id/ToggleButton0"
android:layout_width="96dp"
android:layout_height="wrap_content"
android:checked="true"
android:background="@drawable/widget_tab_header_button_background" />
<ToggleButton
android:id="@+id/ToggleButton1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/widget_tab_header_button_background" />
<ToggleButton
android:id="@+id/ToggleButton2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/widget_tab_header_button_background" />
<ToggleButton
android:id="@+id/ToggleButton3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/widget_tab_header_button_background" />
<ToggleButton
android:id="@+id/ToggleButton4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/widget_tab_header_button_background" />
<ToggleButton
android:id="@+id/ToggleButton5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/widget_tab_header_button_background" />
</LinearLayout>
2. As you may have noticed, I've put several Toggle Buttons into the layout. Since they are buttons, they should display differently when user pressing it or ticking it. So I need to create a background definition file for them.
Add a new XML file named "widget_tab_header_button_background.xml" in the folder "app -> res -> drawable", and put the following text in:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_checked="true" android:state_pressed="true">
<shape>
<gradient android:angle="270" android:endColor="#ffc2b7" android:startColor="#ffc2b7" />
<stroke android:width="2dp" android:color="#dcdcdc" />
<corners android:radius="2dp" />
<padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
</shape>
</item>
<item android:state_checked="true">
<shape>
<gradient android:angle="270" android:endColor="#ff9d77" android:startColor="#ff9d77" />
<stroke android:width="2dp" android:color="#fad3cf" />
<corners android:radius="2dp" />
<padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
</shape>
</item>
<item>
<shape>
<gradient android:angle="270" android:endColor="#ff9d77" android:startColor="#ff9d77" />
<stroke android:width="2dp" android:color="#FF000000" />
<corners android:radius="2dp" />
<padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
</shape>
</item>
</selector>
3. Add a new class named "TabHeaderView" in the folder "app -> java -> com.casperlee.personalexpense -> widgets", and put the following code in:
package com.casperlee.personalexpense.widgets;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ToggleButton;
import com.casperlee.personalexpense.R;
import java.util.ArrayList;
import java.util.List;
public class TabHeaderView extends LinearLayout {
// Fields
private static final int MAX_TAB_COUNT = 6;
private static final int DEFAULT_TAB_COUNT = 2;
private Layout ui;
private Context context;
private OnTabChangeListener listener;
// Entrances
public TabHeaderView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
this.initFields();
this.createLayout(attrs);
this.initLayout();
this.setListeners();
}
// Interfaces
public interface OnTabChangeListener {
public abstract boolean onTabChanging(int tabIndex);
public abstract void onTabChanged(int tabIndex);
}
// Properties
private int tabCount;
public int getTabCount() {
return tabCount;
}
public void setTabCount(int tabCount) {
this.tabCount = tabCount;
for (int i = 0; i < MAX_TAB_COUNT; i++) {
if (i < tabCount) {
this.ui.toggleButtons.get(i).setVisibility(View.VISIBLE);
} else {
this.ui.toggleButtons.get(i).setVisibility(View.GONE);
}
}
this.invalidate();
}
// Public methods
public void setTabChangeListener(OnTabChangeListener l) {
this.listener = l;
}
public void setTabCaption(int tabIndex, String caption) {
if (tabIndex < 0 || tabIndex >= MAX_TAB_COUNT) {
return;
}
this.ui.toggleButtons.get(tabIndex).setTextOff(caption);
this.ui.toggleButtons.get(tabIndex).setTextOn(caption);
this.invalidate();
}
// Private methods
private void initFields() {
this.tabCount = DEFAULT_TAB_COUNT;
}
private void createLayout(AttributeSet attrs) {
View v = inflate(this.context,
R.layout.widget_tab_header_view_layout, null);
v.setLayoutParams(new LayoutParams(this.context, attrs));
this.addView(v, 0);
this.ui = new Layout();
}
private void initLayout() {
this.setTabCount(this.tabCount);
}
private void setListeners() {
this.setViewClickListeners();
}
private void setViewClickListeners() {
OnMyViewClickListener l = new OnMyViewClickListener();
for (int i = 0; i < MAX_TAB_COUNT; i++) {
this.ui.toggleButtons.get(i).setOnClickListener(l);
}
}
// Classes
private class Layout {
private ToggleButton ToggleButton0 = null;
private ToggleButton ToggleButton1 = null;
private ToggleButton ToggleButton2 = null;
private ToggleButton ToggleButton3 = null;
private ToggleButton ToggleButton4 = null;
private ToggleButton ToggleButton5 = null;
private List<ToggleButton> toggleButtons = null;
public Layout() {
this.initialize();
}
private void initialize() {
this.ToggleButton0 = (ToggleButton)TabHeaderView.this.findViewById(R.id.ToggleButton0);
this.ToggleButton1 = (ToggleButton)TabHeaderView.this.findViewById(R.id.ToggleButton1);
this.ToggleButton2 = (ToggleButton)TabHeaderView.this.findViewById(R.id.ToggleButton2);
this.ToggleButton3 = (ToggleButton)TabHeaderView.this.findViewById(R.id.ToggleButton3);
this.ToggleButton4 = (ToggleButton)TabHeaderView.this.findViewById(R.id.ToggleButton4);
this.ToggleButton5 = (ToggleButton)TabHeaderView.this.findViewById(R.id.ToggleButton5);
this.toggleButtons = new ArrayList<ToggleButton>();
this.toggleButtons.add(this.ToggleButton0);
this.toggleButtons.add(this.ToggleButton1);
this.toggleButtons.add(this.ToggleButton2);
this.toggleButtons.add(this.ToggleButton3);
this.toggleButtons.add(this.ToggleButton4);
this.toggleButtons.add(this.ToggleButton5);
}
}
private class OnMyViewClickListener implements View.OnClickListener {
@Override
public void onClick(View v) {
for (int i = 0; i < MAX_TAB_COUNT; i++) {
ToggleButton btn = TabHeaderView.this.ui.toggleButtons.get(i);
if (v == btn) {
if (!btn.isChecked()) {
btn.setChecked(true);
} else {
if (listener != null) {
listener.onTabChanged(i);
}
}
} else {
btn.setChecked(false);
}
}
}
}
}
4. Done!