以Android Calculator源码为例,自定义一个ColorButton,这个ColorButton具有自定义的UI和事件响应能力:
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.calculator2;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.util.AttributeSet;
import android.widget.Button;
import android.view.View.OnClickListener;
import android.view.View;
import android.view.MotionEvent;
import android.content.res.Resources;
/**
* Button with click-animation effect.
*/
class ColorButton extends Button implements OnClickListener {
int CLICK_FEEDBACK_COLOR;
static final int CLICK_FEEDBACK_INTERVAL = 10;
static final int CLICK_FEEDBACK_DURATION = 350;
float mTextX;
float mTextY;
long mAnimStart;
OnClickListener mListener;
Paint mFeedbackPaint;
public ColorButton(Context context, AttributeSet attrs) {
super(context, attrs);
Calculator calc = (Calculator) context;
init(calc);
mListener = calc.mListener;
setOnClickListener(this);
}
public void onClick(View view) {
mListener.onClick(this);
}
private void init(Calculator calc) {
Resources res = getResources();
CLICK_FEEDBACK_COLOR = res.getColor(R.color.magic_flame);
mFeedbackPaint = new Paint();
mFeedbackPaint.setStyle(Style.STROKE);
mFeedbackPaint.setStrokeWidth(2);
getPaint().setColor(res.getColor(R.color.button_text));
mAnimStart = -1;
}
@Override
public void onSizeChanged(int w, int h, int oldW, int oldH) {
measureText();
}
private void measureText() {
Paint paint = getPaint();
mTextX = (getWidth() - paint.measureText(getText().toString())) / 2;
mTextY = (getHeight() - paint.ascent() - paint.descent()) / 2;
}
@Override
protected void onTextChanged(CharSequence text, int start, int before, int after) {
measureText();
}
private void drawMagicFlame(int duration, Canvas canvas) {
int alpha = 255 - 255 * duration / CLICK_FEEDBACK_DURATION;
int color = CLICK_FEEDBACK_COLOR | (alpha << 24);
mFeedbackPaint.setColor(color);
canvas.drawRect(1, 1, getWidth() - 1, getHeight() - 1, mFeedbackPaint);
}
@Override
public void onDraw(Canvas canvas) {
if (mAnimStart != -1) {
int animDuration = (int) (System.currentTimeMillis() - mAnimStart);
if (animDuration >= CLICK_FEEDBACK_DURATION) {
mAnimStart = -1;
} else {
drawMagicFlame(animDuration, canvas);
postInvalidateDelayed(CLICK_FEEDBACK_INTERVAL);
}
} else if (isPressed()) {
drawMagicFlame(0, canvas);
}
CharSequence text = getText();
canvas.drawText(text, 0, text.length(), mTextX, mTextY, getPaint());
}
public void animateClickFeedback() {
mAnimStart = System.currentTimeMillis();
invalidate();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean result = super.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
animateClickFeedback();
break;
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_CANCEL:
invalidate();
break;
}
return result;
}
}
在main.xml中引用该自定义控件( com.android.calculator2.ColorButton ):
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
* Copyright (C) 2008, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ff000000">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2"
>
<com.android.calculator2.CalculatorDisplay
android:id="@+id/display"
android:layout_width="0dp"
android:layout_weight="5"
android:layout_height="match_parent"
maxDigits="@integer/max_digits">
<com.android.calculator2.CalculatorEditText
style="@style/display_style" />
<com.android.calculator2.CalculatorEditText
style="@style/display_style" />
</com.android.calculator2.CalculatorDisplay>
<ImageButton android:id="@+id/overflow_menu"
android:layout_width="48dip"
android:layout_height="match_parent"
android:src="@drawable/ic_menu_overflow"
android:background="@android:color/transparent"
android:layout_marginLeft="8dip"
android:visibility="gone"/>
<FrameLayout
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent">
<!-- marginRight has to be 0 to catch border-touch -->
<<com.android.calculator2.ColorButton
android:id="@+id/clear"
android:text="@string/clear"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginRight="0dp"
android:textSize="15dp"
style="@style/button_style"
/>
<!-- marginRight has to be 0 to catch border-touch -->
<com.android.calculator2.ColorButton
android:id="@+id/del"
android:text="@string/del"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginRight="0dp"
android:textSize="15dp"
style="@style/button_style"
/>
</FrameLayout>
</LinearLayout>
<android.support.v4.view.ViewPager
android:id="@+id/panelswitch"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="4"
/>
</LinearLayout>
官方教程:http://developer.android.com/guide/topics/ui/custom-components.html