ios一些控件还是挺漂亮的,但是对android程序员来说可能比较苦逼,因为ios一些看起来简单的效果对android来说可能就没那么简单了,但是没办法很多产品都是拿ios的一些控件叫android开发人员来照着做,今天就来做一个设置中常见的开关效果,
思路:
1:准备二张图片 一个是包含开和关二种状态的图片,一个是上面滑动的按钮图片
2:这些图片肯定是不能通过原生态的控件显示上去的,要通过canvas画上去
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"
>
<com.example.toggle.ui.MyToggleView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
/>
</RelativeLayout>
MyToggleView.java 自定义的控件
package com.example.toggle.ui;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import com.example.toggle.R;
/**
* 一个view从创建到显示要经历的过程
* 1:构造函数 实例初始化
* 2:测量 onMeasure
* 3:如果当前view是ViewGroup 还要义务测量它孩子(子view)
* 4:指定控件的大小和位置 (onLayout)
* 如果当前view是ViewGroup 还要义务指定它孩子的大小和位置(子view)
* 5:绘制(就是画出来再屏幕上可见)onDraw(Canvas canvas)
* @author Administrator
*
* 点击事件包含点击 和 离开 而这个离开刚好和移动中的up事件一样
*
*/
public class MyToggleView extends View implements View.OnClickListener {
private static final String TAG = "MyToggleView";
Paint paint ;
private Bitmap bg_bitmap;
private Bitmap sliding_bitmap;
private float slidingLeft = 0;
private int slideLeftMax;
/**
* 自定义样式用它
* @param context
* @param attrs
* @param defStyleAttr
*/
public MyToggleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/**
* 在布局时候用它
* @param context
* @param attrs
*/
public MyToggleView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
private void initView() {
paint = new Paint();
bg_bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.switch_background);
sliding_bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.slide_button);
slideLeftMax = bg_bitmap.getWidth() - sliding_bitmap.getWidth();
setOnClickListener(this);
}
/**
* 在代码new的时候用它
* @param context
*/
public MyToggleView(Context context) {
super(context);
}
/**
* 测量
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
/**
* 这是父类去测量子view的大小 而我们可以不要父类去测量
*/
// super.onMeasure(bg_bitmap.getWidth(), bg_bitmap.getHeight());
/**
* 人为指定控件测量大小 (就是说没有测量)
*/
setMeasuredDimension(bg_bitmap.getWidth(), bg_bitmap.getHeight());
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(bg_bitmap, 0, 0, paint);
canvas.drawBitmap(sliding_bitmap, slidingLeft , 0, paint);
}
private boolean isOpened = false;
/**
* isClickenble为true表示点击事件生效 但触摸事件无效
* isClickenble 为false表示点击事件失效 触摸事件有效
*/
private boolean isClickenble = false;
@Override
public void onClick(View v) {
if(isClickenble){
isOpened = !isOpened;
if(isOpened){
slidingLeft = bg_bitmap.getWidth()-sliding_bitmap.getWidth();
}else{
slidingLeft = 0;
}
invalidate();
}
}
private float startX = 0;//手指刚触动时候的x轴坐标
private float lastX = 0;//手指刚触动时候的x轴坐标
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);//执行父类的方法
switch (event.getAction()) {//判断滑动的动作 是刚按下 还是拖动 还是手指 抬起
case MotionEvent.ACTION_DOWN :
lastX = startX = event.getX();//这是距离 这个控件的x轴坐标值
isClickenble = true;
break;
case MotionEvent.ACTION_MOVE :
float endX = event.getX();
int distanceX = (int) Math.abs(endX - lastX);
if(distanceX > 5){
isClickenble = false;
}
refreshView(endX);
startX = event.getX();//重新计算初始值
break;
case MotionEvent.ACTION_UP :
if(slidingLeft>slideLeftMax/2){ //开
isOpened = true;
slidingLeft = slideLeftMax;
}else{//关
isOpened = false;
slidingLeft = 0;
}
invalidate();
break;
}
return true;//表示自己处理 不需要调用父类的方法
}
private void refreshView(float endX) {
float distance = (endX - startX) ;
slidingLeft+=distance;
if(slidingLeft<0){
slidingLeft = 0;
}
if(slidingLeft>slideLeftMax){
slidingLeft = slideLeftMax;
}
invalidate();
}
}
效果图: