自定义控件基本有两种
1继承View主要针对单个不包括子控件的控件,类似于button,ImageView等
2继承viewGroup针对有子控件的控件,类似于RelativeLayout,ListView等
自定义控件的基本思路
一个视图从创建到显示过程中的主要方法
1.构造方法实例化类
2.测量-measure(int,int)-->onMeasure();
如果当前View是一个ViewGroup,还有义务测量孩子
孩子有建议权
3.指定位置-layout()-->onLayout();
指定控件的位置,一般View不用写这个方法,ViewGroup的时候才需要,一般View不需要重写该方法
4.绘制视图--draw()-->onDraw(canvas)
根据上面两个方法参数,进入绘制
下面是一个简单例子,自定义一个开关
效果图:
项目结构:
activity_main.xml中
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
>
<com.example.myself.MyToggleButton
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
/>
</RelativeLayout>
MyToggleButton中
package com.example.myself;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
* 作者:杨光福 on 2016/5/14 16:27
* 微信:yangguangfu520
* QQ号:541433511
* 一个视图从创建到显示过程中的主要方法
* //1.构造方法实例化类
* //2.测量-measure(int,int)-->onMeasure();
* 如果当前View是一个ViewGroup,还有义务测量孩子
* 孩子有建议权
* //3.指定位置-layout()-->onLayout();
* 指定控件的位置,一般View不用写这个方法,ViewGroup的时候才需要,一般View不需要重写该方法
* //4.绘制视图--draw()-->onDraw(canvas)
* 根据上面两个方法参数,进入绘制
*/
public class MyToggleButton extends View implements View.OnClickListener {
// 背景图片
private Bitmap backgroundBitmap;
// 按钮
private Bitmap slidingBitmap;
// 画笔对象
private Paint paint;
// 距离左边的距离
private int slideLeft;
// 距离左边最大距离
private int slidLeftMax;
// 是否打开
private boolean isOpen = false;
/**
* 自定义控件的时候,两个构造方法都要重写
* 代码中调用的
* @param context
*/
public MyToggleButton(Context context) {
// 调MyToggleButton(Context context, AttributeSet attrs)
this(context,null);
}
/**
* 布局文件中调用的
* 如果我们在布局文件使用该类,将会用这个构造方法实例该类,如果没有就崩溃
* @param context
* @param attrs
*/
public MyToggleButton(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
/**
* 初始化控件
*/
private void initView() {
paint = new Paint();
//设置抗锯齿,就是图像边缘平滑
paint.setAntiAlias(true);
// 背景
backgroundBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.switch_background);
// 上面按钮
slidingBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.slide_button);
// 距左边的距离
slidLeftMax = backgroundBitmap.getWidth() - slidingBitmap.getWidth();
//点击事件
setOnClickListener(this);
}
/**
* 视图的测量
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 得到的参数是控件的宽高
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 设置宽高
setMeasuredDimension(backgroundBitmap.getWidth(), backgroundBitmap.getHeight());
}
/**
* 绘制
* @param canvas
*/
@Override
protected void onDraw(Canvas canvas) {
// super.onDraw(canvas);
// 背景
canvas.drawBitmap(backgroundBitmap,0,0,paint);
// 上面的滑动按钮
canvas.drawBitmap(slidingBitmap, slideLeft, 0, paint);
}
/**
* 点击事件
* true:点击事件生效,滑动事件不生效
* false:点击事件不生效,滑动事件生效
*/
@Override
public void onClick(View v) {
isOpen = !isOpen;
flushView();
}
/**
* 设置靠左边的距离
*/
private void flushView() {
if(isOpen){
slideLeft = slidLeftMax;
}else{
slideLeft = 0;
}
//会导致onDraw()执行,重新绘制图像
invalidate();
}
}
参考视频
http://www.gulixueyuan.com/course/124/learn#lesson/1905