首先上效果图
第一张图是进入该界面的效果,顶部是一个viewpager,下面每个块都是自定义的view HomeButton,第二张图是点击右边第一个方块的效果,点击时方块整体有收缩的效果,中间会显示手印,手指抬起时又恢复原样。
在之前的一篇文章 Android view绘制流程已经详细介绍了view的绘制流程,这里不多说,除了知道view的绘制流程外,我们还应该落实到实处,要做好自定义view当然要熟悉drawable和canvas,多在这两块下功夫,然后可能需要加上一些小技巧,本文的例子主要是用canvas和matrix加上动画做的效果,这里贴一下关于Matrix的介绍。
关于Matrix
Matrix的对图像的处理可分为四类基本变换:
Translate 平移变换
Rotate 旋转变换
Scale 缩放变换
Skew 错切变换
除平移变换(Translate)外,旋转变换(Rotate)、缩放变换(Scale)和错切变换(Skew)都可以围绕一个中心点来进行,如果不指定,在默认情况下是围绕(0, 0)来进行相应的变换的。
针对每种变换,Android提供了pre、set和post三种操作方式。其中
set用于设置Matrix中的矩阵值。
pre是先乘,post是后乘,因为矩阵的乘法不满足交换律,因此先乘、后乘必须要严格区分。先乘相当于矩阵运算中的右乘。后乘相当于矩阵运算中的左乘。
事实上,图像处理时,矩阵的运算是从右边往左边方向进行运算的。这就形成了越在右边的矩阵(右乘),越先运算(先乘),反之亦然。
post是后乘,当前的矩阵乘以参数给出的矩阵。可以连续多次使用post,来进行多种变换。例如,需要将图片旋转60度,然后平移到(100,,100)的地方,那么可以这样做:
Matrix m = new Matrix();
m.postRotate(60);
m.postTranslate(100,100);
这样就达到了效果。
pre是前乘,参数给出的矩阵乘以当前的矩阵。上面的例子,如果使用pre的话就要这样做:
Matrix m = new Matrix();
m.setTranslate(100,100);
m.preRotate(60);
主要代码
HomeButton类,自定义view继承ImageView
package com.chm.test.view;
import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;
import android.widget.ImageView;
import com.chm.test.R;
import com.chm.test.myInterface.HomeClickListener;
import com.chm.test.utils.BitmapUtils;
public class HomeButton extends ImageView {
private Bitmap bitmap;
private Bitmap home_flight;
private Bitmap label_new;
private int state = 0; //是否按下
private int color;
private float textsize;
private boolean big;
private int home;
private String text;
private int screenW;
private int screenH;
//点击事件
private HomeClickListener listener = null;
private int[] colors = {getResources().getColor(R.color.red),
getResources().getColor(R.color.orange),
getResources().getColor(R.color.blue),
getResources().getColor(R.color.purple),
getResources().getColor(R.color.air),
getResources().getColor(R.color.texi),
getResources().getColor(R.color.jingdian)};
private Bitmap[] bitmaps = {
BitmapFactory.decodeResource(getResources(), R.drawable.home_hotel),
BitmapFactory.decodeResource(getResources(),
R.drawable.home_groupbuy),
BitmapFactory.decodeResource(getResources(), R.drawable.home_train),
BitmapFactory.decodeResource(getResources(),
R.drawable.home_lastmin),
BitmapFactory
.decodeResource(getResources(), R.drawable.home_flight),
BitmapFactory.decodeResource(getResources(), R.drawable.home_car),
BitmapFactory.decodeResource(getResources(),
R.drawable.home_scenery)
};
public HomeButton(Context context) {
super(context);
}
public HomeButton(Context context, AttributeSet attrs) {
super(context, attrs);
bitmap = BitmapUtils.zoomImage(BitmapFactory.decodeResource(
getResources(), R.drawable.fingerprint), 127, 122);
label_new = BitmapFactory.decodeResource(getResources(), R.drawable.label_new);
TypedArray typedArray = context.obtainStyledAttributes(attrs,
R.styleable.HomeButton);
color = typedArray.getInt(R.styleable.HomeButton_backcolor, 0);
textsize = typedArray.getDimension(R.styleable.HomeButton_textSize, 24);
big = typedArray.getBoolean(R.styleable.HomeButton_big, true);
home = typedArray.getInt(R.styleable.HomeButton_home, 0);
text = typedArray.getString(R.styleable.HomeButton_text);
System.out.println("color:" + color + " textsize:" + textsize + " big:"
+ big + " home:" + home);
home_flight = bitmaps[home];
screenW = ((Activity) context).getWindow().getWindowManager()
.getDefaultDisplay().getWidth() / 2 - 16;
if (big) {
screenH = screenW;
} else {
screenH = screenW / 2 - 4;
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 重新设置View大小
setMeasuredDimension(screenW, screenH);
}
/*
* orange 2182F7 light red 7359EF 紫 B551A5 Blue CE8A39 air CEBE00 texi
* 9CAA00 jingdian 00AA73
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(colors[color]);
Paint paint = new Paint();
paint.setColor(Color.WHITE);
paint.setTextSize(24);
if (big) {
Matrix matrix = new Matrix();
matrix.postTranslate(this.getWidth() / 2 - home_flight.getWidth()
/ 2, this.getHeight() / 2 - home_flight.getHeight() / 2);
canvas.drawText(text, 10, 40, paint);
canvas.drawBitmap(home_flight, matrix, paint);
} else {
Matrix matrix_small = new Matrix();
matrix_small.postTranslate(10, this.getHeight() / 2 - home_flight.getHeight() / 2);
canvas.drawBitmap(home_flight, matrix_small, new Paint());
if (home == 3) {
paint.setTextSize(16);
canvas.drawText("夜宵酒店", home_flight.getWidth() + 20, this.getHeight() / 2 - home_flight.getHeight() / 2 + 10, paint);
canvas.drawText("加载中...", home_flight.getWidth() + 20, this.getHeight() / 2 + home_flight.getHeight() / 2, paint);
} else if (home == 5) {
paint.setTextSize(16);
canvas.drawText("送机", home_flight.getWidth() + 20, this.getHeight() / 2 - home_flight.getHeight() / 2 + 10, paint);
canvas.drawText("免费叫出租", home_flight.getWidth() + 20, this.getHeight() / 2 + home_flight.getHeight() / 2, paint);
} else {
canvas.drawText(text, home_flight.getWidth() + 20, this.getHeight() / 2 + home_flight.getHeight() / 2, paint);
}
if (home == 6) {
Matrix matrix_new = new Matrix();
matrix_new.postTranslate(screenW - label_new.getWidth(), 0);
canvas.drawBitmap(label_new, matrix_new, new Paint());
}
}
//按下
if (state == 1) {
Matrix matrix2 = new Matrix();
matrix2.postTranslate(this.getWidth() / 2 - bitmap.getWidth() / 2,
this.getHeight() / 2 - bitmap.getHeight() / 2);
canvas.drawBitmap(bitmap, matrix2, new Paint());
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float start = 1.0f;
float end = 0.95f;
Animation scaleAnimation = new ScaleAnimation(start, end, start, end,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
Animation endAnimation = new ScaleAnimation(end, start, end, start,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
scaleAnimation.setDuration(200);
scaleAnimation.setFillAfter(true);
endAnimation.setDuration(200);
endAnimation.setFillAfter(true);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
this.startAnimation(scaleAnimation);
state = 1;
invalidate();
break;
case MotionEvent.ACTION_UP:
this.startAnimation(endAnimation);
state = 0;
invalidate();
if (listener != null) {
listener.onclick();
}
break;
// 滑动出去不会调用action_up,调用action_cancel
case MotionEvent.ACTION_CANCEL:
this.startAnimation(endAnimation);
state = 0;
invalidate();
break;
}
// 不返回true,Action_up就响应不了
return true;
}
/**
* 加入响应事件
*
* @param clickListener
*/
public void setOnHomeClick(HomeClickListener clickListener) {
this.listener = clickListener;
}
}
HomeClickListener接口
public interface HomeClickListener {
public void onclick();
}
HotelActivity类
package com.chm.test;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import com.chm.mylibrary.BaseActivity;
import com.chm.test.adapter.ViewPagerAdapter;
import com.chm.test.myInterface.HomeClickListener;
import com.chm.test.utils.BitmapUtils;
import com.chm.test.view.HomeButton;
import java.util.ArrayList;
import java.util.List;
public class HotelActivity extends BaseActivity implements View.OnClickListener,ViewPager.OnPageChangeListener {
private ViewPager vp;
private ViewPagerAdapter vpAdapter;
private List<View> views;
private int width;
private int height;
private RelativeLayout relativeLayout;
// 引导图片资源
private static final int[] pics = { R.drawable.home1, R.drawable.home2,
R.drawable.home3, R.drawable.home4 };
// 底部小店图片
private ImageView[] dots;
// 记录当前选中位置
private int currentIndex;
private View view;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.index);
HomeButton button = (HomeButton) findViewById(R.id.hotel);
button.setOnHomeClick(new HomeClickListener() {
@Override
public void onclick() {
Intent intent =new Intent();
intent.setClass(HotelActivity.this, HotelActivity.class);
startActivity(intent);
}
});
//等到屏幕的大小
width = this.getWindowManager().getDefaultDisplay().getWidth();
//以670*240的图片为例,正常中不要这样用
height =width*240/670;
relativeLayout =(RelativeLayout) findViewById(R.id.relative);
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) relativeLayout.getLayoutParams();
layoutParams.width =width;
layoutParams.height =height;
relativeLayout.setLayoutParams(layoutParams);
views = new ArrayList<View>();
LinearLayout.LayoutParams mParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
// 初始化引导图片列表
for (int i = 0; i < pics.length; i++) {
ImageView iv = new ImageView(this);
iv.setLayoutParams(mParams);
//改变大小
// iv.setImageResource(pics[i]);
iv.setImageBitmap(BitmapUtils.zoomImage(BitmapFactory.decodeResource(getResources(), pics[i]), width, height));
views.add(iv);
}
vp = (ViewPager) findViewById(R.id.viewpager);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(width, height);
params.leftMargin=10;
params.topMargin=10;
params.rightMargin=10;
vp.setLayoutParams(params);
// 初始化Adapter
vpAdapter = new ViewPagerAdapter(views);
vp.setAdapter(vpAdapter);
// 绑定回调
vp.setOnPageChangeListener(this);
// 初始化底部小点
initDots();
}
private void initDots() {
LinearLayout ll = (LinearLayout) findViewById(R.id.ll);
dots = new ImageView[pics.length];
// 循环取得小点图片
for (int i = 0; i < pics.length; i++) {
dots[i] = (ImageView) ll.getChildAt(i);
dots[i].setEnabled(true);// 都设为灰色
dots[i].setOnClickListener(this);
dots[i].setTag(i);// 设置位置tag,方便取出与当前位置对应
}
currentIndex = 0;
dots[currentIndex].setEnabled(false);// 设置为白色,即选中状态
}
/**
* 设置当前的引导页
*/
private void setCurView(int position) {
if (position < 0 || position >= pics.length) {
return;
}
vp.setCurrentItem(position);
}
/**
* 这只当前引导小点的选中
*/
private void setCurDot(int positon) {
if (positon < 0 || positon > pics.length - 1 || currentIndex == positon) {
return;
}
dots[positon].setEnabled(false);
dots[currentIndex].setEnabled(true);
currentIndex = positon;
}
// 当滑动状态改变时调用
@Override
public void onPageScrollStateChanged(int arg0) {
}
// 当当前页面被滑动时调用
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
vp.requestDisallowInterceptTouchEvent(true);
}
// 当新的页面被选中时调用
@Override
public void onPageSelected(int arg0) {
// 设置底部小点选中状态
setCurDot(arg0);
}
@Override
public void onClick(View view) {
int position = (Integer) view.getTag();
setCurView(position);
setCurDot(position);
}
}
布局文件index.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:ptr="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#545454"
android:orientation="vertical" >
<RelativeLayout
android:id="@+id/relative"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp" />
<LinearLayout
android:id="@+id/ll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:orientation="horizontal" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:clickable="true"
android:padding="15.0dip"
android:src="@drawable/dot" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:clickable="true"
android:padding="15.0dip"
android:src="@drawable/dot" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:clickable="true"
android:padding="15.0dip"
android:src="@drawable/dot" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:clickable="true"
android:padding="15.0dip"
android:src="@drawable/dot" />
</LinearLayout>
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:orientation="vertical" >
<com.chm.test.view.HomeButton
android:id="@+id/hotel"
android:layout_width="300dp"
android:layout_height="300dp"
android:background="#aaa"
ptr:backcolor="0"
ptr:big="true"
ptr:home="0"
ptr:text="酒店"
ptr:textSize="24sp" />
<com.chm.test.view.HomeButton
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_marginTop="8dp"
android:background="#aaa"
ptr:backcolor="1"
ptr:big="true"
ptr:home="1"
ptr:text="团购"
ptr:textSize="24sp" />
<com.chm.test.view.HomeButton
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_marginTop="8dp"
android:background="#aaa"
ptr:backcolor="2"
ptr:big="false"
ptr:home="2"
ptr:text="火车票"
ptr:textSize="24sp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="8dp"
android:orientation="vertical" >
<com.chm.test.view.HomeButton
android:layout_width="200dp"
android:layout_height="200dp"
ptr:backcolor="3"
ptr:big="false"
ptr:home="3"
ptr:text="团购"
ptr:textSize="24sp" />
<com.chm.test.view.HomeButton
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_marginTop="8dp"
android:background="#aaa"
ptr:backcolor="4"
ptr:big="true"
ptr:home="4"
ptr:text="机票"
ptr:textSize="24sp" />
<com.chm.test.view.HomeButton
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_marginTop="8dp"
ptr:backcolor="5"
ptr:big="false"
ptr:home="5"
ptr:text="送机"
ptr:textSize="24sp" />
<com.chm.test.view.HomeButton
android:layout_width="200dp"
android:layout_height="200dp"
ptr:backcolor="6"
android:layout_marginTop="8dp"
ptr:big="false"
ptr:home="6"
ptr:text="景点门户"
ptr:textSize="24sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</ScrollView>