您的位置:首页 > 其它

Andriod下完全自定义控件和在自定义控件中使用自定义属性

2016-07-22 00:16 453 查看
首先,自定义控件分为三类:

自定义的组合控件

继承View的自定义控件

继承ViewGroup的自定义控件

在这里,我要写的是第二种,也就是继承自View的自定义控件,第一种自定义的组合控件,我已经写过了,可以在我的博客中可以找到

现在来看一下继承View的自定义控件

首先,需要写一个类继承自View,那么,它也有三个构造方法,有一个参数的构造方法实在代码中new这个自定义控件时被调用;有两个参数的构造方法是在布局中使用这个自定义控件的时候调用,有三个参数的构造方法,实在使用到这个自定义控件的样式时被调用;同样,用到那个就重写那个

其次,需要重写onMeasure()方法和onDraw()方法

onMeasure()方法是为了测量控件自己的宽高,onDraw()方法是为了绘制的内容,如果你继承的是ViewGroup,那么你还需要重写onLayout()方法

最后,实现业务逻辑

在这里,我实现的是一个开关的效果

如下图:



这是可以滑动和点击的

自定义属性的步骤,具体请参考我的自定义的组合控件,哪里已经做了详细说明

1、先自定义一个类继承View

// 在代码中创建控件
public MyButton(Context context) {
super(context);
}

// 控件使用在xml布局文件中
public MyButton(Context context, AttributeSet attrs) {
super(context, attrs);
}

// 使用样式时
public MyButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}


接下来,你需要在布局中使用这个控件,用全类名

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:abc="http://schemas.android.com/apk/res/com.abc.togglestate"
android:layout_width="match_parent"
android:layout_height="match_parent"
>

<com.wdj.togglestate.ui.MyButton
android:id="@+id/mybutton"
android:layout_width="match_parent"
android:layout_height="match_parent"
abc:state="false"
abc:backgroundRes="@drawable/switch_background"
abc:slideButtonRes="@drawable/slide_button_background"
/>

</RelativeLayout>


2、重写onMeasure()方法

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//把背景图片的宽高作为控件的宽高
setMeasuredDimension(mSwitchBackground.getWidth(), mSwitchBackground.getHeight());
}


3、重写onDraw()方法

@Override
protected void onDraw(Canvas canvas) {

super.onDraw(canvas);
canvas.drawBitmap(mSwitchBackground, 0, 0, null);
if(!isTouching){
//根据当前状态滑动图片
int left = 0;
if(currentToggleState){ //如果是打开状态,左边距等于背景的宽度-滑块的宽度
left = mSwitchBackground.getWidth() - mSlideButton.getWidth();
}else {
//关闭状态
left = 0;
}
canvas.drawBitmap(mSlideButton, left, 0, null);
}else{
//根据手指触摸的位置,绘制滑动的图片
int left = currentX - mSlideButton.getWidth() / 2;      //为了让用户感觉手在图片中间滑动
if(left < 0){  //图片超出左边界,直接绘制到0位置
left = 0;
}else if(left >= mSwitchBackground.getWidth() - mSlideButton.getWidth()){  //图片超出右边界,直接绘制到右边
left = mSwitchBackground.getWidth() - mSlideButton.getWidth();
}
canvas.drawBitmap(mSlideButton, left, 0, null);
}

}


接下来就是处理自己的业务逻辑

在这里,我把代码全部放在这里了,这是MyButton .java

 public class MyButton extends View {

private Bitmap mSwitchBackground;
private Bitmap mSlideButton;
private boolean currentToggleState; //记录当前开关的状态
private int currentX;
private boolean isTouching = false; //记录当前控件是否处于触摸中
private MyButtonOnStateChangedListener listener;

private String namespace = "http://schemas.android.com/apk/res/com.abc.togglestate";

/**
* 在代码中创建控件调用
* @param context,
*/
public MyButton(Context context) {
super(context);

}

/**
* 控件使用在xml布局中使用
* @param context
* @param attrs
*/
public MyButton(Context context, AttributeSet attrs) {
super(context, attrs);
//获取布局文件中的属性
int backgroundRes = attrs.getAttributeResourceValue(namespace, "backgroundRes",0);
setBackgroundRes(backgroundRes);

int slideButtonRes = attrs.getAttributeResourceValue(namespace, "slideButtonRes", 0);
setSlidButtonBackgroundRes(slideButtonRes);

currentToggleState = attrs.getAttributeBooleanValue(namespace, "state", false);

}

/**
* 使用样式时调用
* @param context
* @param attrs
* @param defStyle
*/
public MyButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);

}

/**
* 测量自己的宽高
*/
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //把背景图片的宽高作为控件的宽高 setMeasuredDimension(mSwitchBackground.getWidth(), mSwitchBackground.getHeight()); }

/**
* 绘制内容
*/
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawBitmap(mSwitchBackground, 0, 0, null); if(!isTouching){ //根据当前状态滑动图片 int left = 0; if(currentToggleState){ //如果是打开状态,左边距等于背景的宽度-滑块的宽度 left = mSwitchBackground.getWidth() - mSlideButton.getWidth(); }else { //关闭状态 left = 0; } canvas.drawBitmap(mSlideButton, left, 0, null); }else{ //根据手指触摸的位置,绘制滑动的图片 int left = currentX - mSlideButton.getWidth() / 2; //为了让用户感觉手在图片中间滑动 if(left < 0){ //图片超出左边界,直接绘制到0位置 left = 0; }else if(left >= mSwitchBackground.getWidth() - mSlideButton.getWidth()){ //图片超出右边界,直接绘制到右边 left = mSwitchBackground.getWidth() - mSlideButton.getWidth(); } canvas.drawBitmap(mSlideButton, left, 0, null); } }

/**
* 给控件设置背景图片
* @param switchBackground
*/
public void setBackgroundRes(int switchBackground) {
mSwitchBackground = BitmapFactory.decodeResource(getResources(),switchBackground);
}

/**
* 给控件设置滑块
* @param slideButtonBackground
*/
public void setSlidButtonBackgroundRes(int slideButtonBackground) {
mSlideButton = BitmapFactory.decodeResource(getResources(), slideButtonBackground);
}

/**
* 开关的状态(这里没有用到)
* 用于外部调用
* @param toggleState
*/
public void isState(boolean toggleState) {
currentToggleState = toggleState;
}

/**
* 处理触摸事件
* 触摸后,获取当前的触摸位置,根据位置,更新控件
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isTouching = true;
currentX = (int) event.getX();
break;

case MotionEvent.ACTION_MOVE:
currentX = (int) event.getX();
break;
case MotionEvent.ACTION_UP:
isTouching = false;
currentX = (int) event.getX();

//手抬起后,更改当前控件的状态,根据当前手触摸的 位置和背景图片的中间值进行比较
boolean tempState = currentX >= mSwitchBackground.getWidth() / 2;
//6.3、判断当前的状态是否发生变化
if(tempState != currentToggleState){
currentToggleState = tempState;
if(listener != null){
listener.OnStateChanged(currentToggleState);
}
}
break;
}
invalidate(); //重新绘制控件,自动触发onDraw(在主线程中绘制控件)
//postInvalidate(); //重新绘制控件,自动触发onDraw(在子线程中绘制控件)
return true; //自己消费事件
}

//6.1、对外提供开关监听
public interface MyButtonOnStateChangedListener{
public void OnStateChanged(boolean state);
}

//6.2、让外界把监听器传进来
public void setMyButtonOnStateChangedListener(MyButtonOnStateChangedListener listener){
this.listener = listener;
}
}


MainActivity.java代码如下

public class MainActivity extends Activity {

private MyButton mybutton;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mybutton = (MyButton) findViewById(R.id.mybutton);
mybutton.setMyButtonOnStateChangedListener(new MyButtonOnStateChangedListener() {

@Override
public void OnStateChanged(boolean state) {
//出来开关状态业务发生变化
Toast.makeText(getApplicationContext(), "" + state, 0).show();
}
});
}
}


希望能对看到这篇博客的小伙伴有所帮助,仅供大家参考
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息