图形绘制之——Canvas详解(3)
前面我们介绍了自定义view中Canvas的基本知识,以及用Bitmap来绘图的方法,但很多情况,我们不光只需要一个好看的界面,还希望它能够响应事件,所以这一节,我们就来讲一下如何,添加一个自定义的监听事件^^
这里我们通过一个例子来讲解:
这个小例子的功能类似我们手机查找联系人,在侧边会有一列字母:a——z,当我们点击它时,会自动找到已这个字母开头的联系人。
这里我们简化一下功能,点击字母或滑到字母时,使屏幕中央放大相应的字母。
不罗嗦,马上来看一下怎么达到效果吧^^:
先来看一下最终的效果:
代码:
一)全部代码展示:
1.自定义View控件:
public class MySlider extends View {
private int width;
private int height;
private Paint paintText;
private float x;
private float y;
private int index=-1;
private Paint paintTextRed;
private String[] arr = new String[]{"a","b","c","d","e","f","g",
"h","i","j","k","l","m","n","o",
"p","q","r","s","t","u","v","w","x","y","z"};
//创建监听器
public interface OnItemSelect{//1.创建一个接口,里面需要实现一个方法
public void OnItemSelected(int index,String indexString);
}
private OnItemSelect listener;//2.创建一个OnItemSelect类型的变量
public void setOnItemSelectListener(OnItemSelect listener) {//3.对上面的接口创建一个实现的方法
this.listener = listener;
}
public MySlider(Context context) {
super(context);
}
public MySlider(Context context, AttributeSet attrs) {//height和width不允许在构造器中使用,都是0,
super(context, attrs);
paintText = new Paint();
paintTextRed =new Paint();
paintTextRed.setColor(Color.RED);
paintText.setTextAlign(Paint.Align.CENTER);
paintTextRed.setTextAlign(Paint.Align.CENTER);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
paintText.setTextSize(height / 26);//先测量后才有值,
paintTextRed.setTextSize(height / 26);
}
//重写onTouch方法
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_MOVE://使滑动或点击时,都出现让字体变红的效果
case MotionEvent.ACTION_DOWN:
x=event.getX();//获得点击的位置(xy)
y=event.getY();
if(x>width-paintText.measureText("m")*2){
index = (int) y/(height/26);
listener.OnItemSelected(index,arr[index]);//4.使用对象listener中的OnItemSelected方法,传入参数
invalidate();
Log.d("onTouch","点击的按钮是:"+arr[index]);
return true;
}
break;
case MotionEvent.ACTION_UP:
index=-1;
invalidate();//每次抬起来也得刷新一次。
break;
}
return super.onTouchEvent(event);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (int i=0;i<26;i++){
if(index!=-1) {
canvas.drawText(arr[index], width - paintText.measureText("m"), height / 26 * (index + 1), paintTextRed);//只将index那位变红色
canvas.drawText(arr[i], width - paintText.measureText("m"), height / 26 * (i + 1), paintText);
}else{
canvas.drawText(arr[i], width - paintText.measureText("m"), height / 26 * (i + 1), paintText);
}
}
}
}
2.主活动的使用:
public class MySliderActivity extends Activity {
private MySlider sliderView;
private TextView textViewSlider;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_slider);
sliderView= (MySlider) findViewById(R.id.sliderview);
textViewSlider= (TextView) findViewById(R.id.textviewSlider);
//5.调用监听器
sliderView.setOnItemSelectListener(new MySlider.OnItemSelect(){
@Override
public void OnItemSelected(int index, String indexString) {
textViewSlider.setText(indexString);//将indexString传到textview中
}//匿名内部类
});//set一个OnItemSelect对象,但它是一个接口,要实现里面的方法,需要子类去实现,这里new一个
}
}
3.使用自定义控件的布局文件:
<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"
tools:context="com.example.day0916.MySliderActivity">
<com.example.day0916.widget.MySlider
android:id="@+id/sliderview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:id="@+id/textviewSlider"
android:layout_width="200dp"
android:layout_height="200dp"
android:textSize="200sp"
android:gravity="center"
android:layout_centerInParent="true"/>
</RelativeLayout>
二)代码分析:
-
onTouchEvent实现触摸事件:
判断事件event.getAction():
MotionEvent.ACTION_DOWN::监听按键按下
MotionEvent.ACTION_MOVE:监听按键划过
MotionEvent.ACTION_UP:监听按键放开
(1)通过事件编号获得事件入口后,先获得点击或滑动的鼠标位置(xy坐标),判断如果在某个位置,则执行下面的代码。
(2)至于点击变红的实现:定义一个index变量,当鼠标up时,值为-1,点击时值为字母在数组中的位置,这样刷新后,通过在onDraw中用不同的画笔绘制就好啦。
- 自定义监听事件:
(1)在自定义控件中,我们建立了一个OnItemSelect接口,且其中必须要实现一个带有两个参数的方法OnItemSelected(),并且,创建了一个设置这个接口的set方法。
(2)在onTouch监听中,每次获得touch后,对原来创建的OnItemSelect对象中的方法,传入参数。
(3)onTouch后,主活动的set方法监听到值,将值传入到textview中进行显示。
这样我们的监听动作就完成啦,这里还要强调一个小要点,我们在自定义控件中需要用到画布的高度和宽度去作为参照设置其他的宽度或高度,比如字体大小的设置,注意的是,这样,字体大小的设置就应该在onMessure中设置,而不应该在构造体中进行。因为构造器在建立时,画布的宽和高都是0,只有在xml布局中设置后,通过onMessure方法才获得了画布的宽、高。