自定义View(二)
- 添加了响应触摸事件;
- 设置接口回调,创建一个状态更新监听;
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;
public class MyView extends View {
private Bitmap backgroundBitmap;
private Bitmap carBitmap;
private Paint paint;
private boolean place = false;
private float currentX;
private OnSwitchStateListener onSwitchStateListener;
public MyView(Context context) {
super(context);
}
public MyView(Context context, AttributeSet attr){
super(context,attr);
paint = new Paint();
//获取配置的资源属性
String namespace = "http://schemas.android.com/apk/res/com.example.myapplication1";
int backgroundResource = attr.getAttributeResourceValue(namespace,"switch_backgroundRoadTarget",-1);
setTarget(backgroundResource);
int carResource = attr.getAttributeResourceValue(namespace,"slide_carImage",-1);
setImage(carResource);
attr.getAttributeBooleanValue(namespace,"switch_state",false);
}
public MyView(Context context, AttributeSet attr,int defStyle){
super(context,attr,defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// super.onMeasure(widthMeasureSpec, heightMeasureSpec);不用此方法,重写父类的方法
setMeasuredDimension(backgroundBitmap.getWidth(),backgroundBitmap.getHeight());
}
@Override
protected void onDraw(Canvas canvas) {//Canvas画板,先绘制在下面,绘制内容都会显示到界面上
super.onDraw(canvas);
//1.绘制背景
canvas.drawBitmap(backgroundBitmap,0,50,paint);
//2.绘制滑块
if(isTouch){
//根据用户触摸位置画滑块
float left = currentX - carBitmap.getWidth()/2.0f;//写2.0f为了精度
int maxLeft = backgroundBitmap.getWidth() - carBitmap.getWidth();
//限定滑块范围
if(left < 0){
left = 0;
}
if(left > maxLeft){
left = maxLeft;
}
canvas.drawBitmap(carBitmap,left,0,paint);
}else{
if(place){//右侧
int roadlong = backgroundBitmap.getWidth() - carBitmap.getWidth();
canvas.drawBitmap(carBitmap,roadlong,0,paint);
}else{//左侧
canvas.drawBitmap(carBitmap,0,0,paint);
}
}
}
boolean isTouch = false;
//重写触摸事件,响应用户的触摸
@Override
public boolean onTouchEvent(MotionEvent event) {
// return super.onTouchEvent(event);在工具类里重写方法
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
isTouch = true;
currentX = event.getX();
break;
case MotionEvent.ACTION_MOVE:
currentX = event.getX();
break;
case MotionEvent.ACTION_UP:
isTouch = false;
currentX = event.getX();
float center = backgroundBitmap.getWidth()/2.0f;
boolean newPlace = currentX > center;//true or false
//若状态变化,通知界面,状态更新
if(place != newPlace && onSwitchStateListener != null){
onSwitchStateListener.onStateUpdate(newPlace);
}
place = newPlace;
break;
default:
break;
}
//重绘界面 onDraw()方法是手动调用
invalidate();//会引发onDraw()方法被调用,变量会重新被调用
return true;
}
public void setTarget(int target) {
backgroundBitmap = BitmapFactory.decodeResource(getResources(),target);
}
public void setImage(int slideImage) {
carBitmap = BitmapFactory.decodeResource(getResources(),slideImage);
}
public void setState(boolean place) {
this.place = place;
}
public interface OnSwitchStateListener{
//状态改变,把状态信息传出去
void onStateUpdate(boolean state);
}
public void setOnSwitchStateListener(OnSwitchStateListener onSwitchStateListener){
this.onSwitchStateListener = onSwitchStateListener;
}
}
理解:
在MyView里声明接口对象
public interface OnSwitchStateListener{
//状态改变,把状态信息传出去
void onStateUpdate(boolean state);
}
添加设置接口对象的方法,外部进行调用
public void setOnSwitchStateListener(OnSwitchStateListener onSwitchStateListener){//界面调用的方法
this.onSwitchStateListener = onSwitchStateListener;
}
状态发生变化,在MyView中合适位置执行接口方法
//若状态变化,通知界面,状态更新
if(place != newPlace && onSwitchStateListener != null){
onSwitchStateListener.onStateUpdate(newPlace);
}
MainActivity里设置状态更新监听
myView.setOnSwitchStateListener(new MyView.OnSwitchStateListener(){
@Override
//匿名类中实现方法onStateUpdate(boolean state)
public void onStateUpdate(boolean state) {
Toast.makeText(getApplicationContext(),"state"+state,Toast.LENGTH_SHORT).show();
}
});
自定义属性
创建attrs.xml
reference:参考某一资源ID。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyView">
<attr name="switch_backgroundRoadTarget" format="reference"/>
<attr name="slide_carImage" format="reference"/>
<attr name="switch_state" format="boolean"/>
</declare-styleable>
</resources>
xml文件里设置属性
xmlns:viewstyle=“http://schemas.android.com/apk/res/com.example.myapplication1”
viewstyle:瞎起的名字,定义属性时需要用
http://schemas.android.com/apk/res/com.example.myapplication1:com.example.myapplication1表示MyView所在的包名
<com.example.myapplication1.MyView
android:id="@+id/smileview"
android:background="#FF0000"
viewstyle:switch_backgroundRoadTarget="@drawable/road1"
viewstyle:slide_carImage="@drawable/car1"
viewstyle:switch_state="false"
android:layout_gravity=“center_vertical”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”/>
在MyView里
public MyView(Context context, AttributeSet attr){
super(context,attr);
paint = new Paint();
//获取配置的资源属性
String namespace = "http://schemas.android.com/apk/res/com.example.myapplication1";
int backgroundResource = attr.getAttributeResourceValue(namespace,"switch_backgroundRoadTarget",-1);
setTarget(backgroundResource);
int carResource = attr.getAttributeResourceValue(namespace,"slide_carImage",-1);
setImage(carResource);
attr.getAttributeBooleanValue(namespace,"switch_state",false);
}
自定义View的使用参考b站上大佬 雇佣兵并的视频。