android自定义控件---仿酷我音乐顶部switch控件

  天天用酷我音乐听歌,有天突然发现它顶部的switch控件其实还是蛮不错的,刚刚才学习了aige大神的自定义控件系列,于是就决定自己也仿一个就当是练练手

效果图没有酷我的好看(尤其是中间的那个圆中的wifi我实在是没有模拟出来),学艺不精让大家见笑了





核心代码如下:

自定义属性,方便个性化

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="slideswitch" >
        <attr name="themeColor" format="color"/>
        <attr name="isOpen" format="boolean" />  
    </declare-styleable>
</resources>

package com.example.slieswitch;

import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
/**
 * 仿酷我音乐顶部switch控件(圆中间的wifi标志不清楚如何画出来的)
 * @author Administrator
 *
 */
public class SlideSwitch extends View {
    private static final String TAG = "SlideSwitch";
    private Context context;
    //默认背景颜色
    private static final int COLOR_THEME = Color.parseColor("#ff00ee00");
    //背景及圆的画笔
    private Paint mPaint;
    //文字画笔
    private TextPaint textPaint;
    private String mStr;// 绘制的文本  
    
    private float mTextSize;// 画笔的文本尺寸 
    //判断开关状态
    private boolean isOpen;
    //临时变量
    private int color_theme;
    //绘制背景的矩形
    private Rect backRect;
   //绘制的圆与背景边缘必须有一定的缝隙,否则就会重合
    private int min_space = 1;
    //绘制的圆心的坐标
    private float circle_x, circle_y;
    //绘制的圆心最左边和最右边的x坐标
    private float centre_right, centre_left;
    //背景的透明度
    private int alpha;
   //手指触摸屏幕时的初始坐标x
    private float eventStartX;
  //手指离开屏幕时的坐标x
    private float eventLastX;
    //文本的起始坐标x和y(最好应该是文本的中心坐标)
    private float text_x,text_y;
    //自定义的handler为了处理invalidate()没有及时响应
    
    private   SlideListener slideListener=null;
    private SlideHander mHander = new SlideHander();

    public interface SlideListener {
	public void open();
	public void close();
    }

    public SlideSwitch(Context context) {
	super(context, null);

    }

    public SlideSwitch(Context context, AttributeSet attrs) {
	super(context, attrs);
	this.context=context;
	mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
//	 calArgs(context);
	
        init();  
	TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.slideswitch);
	color_theme = typedArray.getColor(R.styleable.slideswitch_themeColor, COLOR_THEME);
	isOpen = typedArray.getBoolean(R.styleable.slideswitch_isOpen, false);
	typedArray.recycle();

    }

    public SlideSwitch(Context context, AttributeSet attrs, int defStyleAttr) {
	super(context, attrs, defStyleAttr);
    }
    
    public void setSlideListener(SlideListener slideListener) {  
        this.slideListener = slideListener;  
    }  
    /** 
     * 参数计算 
     *  
     * @param context 
     *            上下文环境引用 
     */  
    private void calArgs(Context context) {  
        // 获取屏幕宽  
        int sreenW = MeasureUtil.getScreenSize((Activity) context)[0];  
  
        // 计算文本尺寸  
        mTextSize = getMeasuredWidth() /10F;
//        Log.e(TAG, "控件的大小="+getMeasuredWidth());
//        Log.e(TAG, "文本字体的大小="+mTextSize);
    }  
    
    private void init(){
        /* 
         * 初始化画笔并设置参数 
         */  
        textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG | Paint.LINEAR_TEXT_FLAG);  
        textPaint.setColor(Color.BLACK);  
//        textPaint.setTextSize(mTextSize);  
//        textPaint.setTextAlign(Paint.Align.CENTER);  
//        textPaint.setTypeface(Typeface.DEFAULT_BOLD);  
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
	// TODO Auto-generated method stub
	super.onMeasure(widthMeasureSpec, heightMeasureSpec);
	int width = getMeasureSize(280, widthMeasureSpec);
	int height = getMeasureSize(140, heightMeasureSpec);
       calArgs(context);
	if (width < height) {
	    width = height * 2;
	}

	setMeasuredDimension(width, height);
	initDraw();
    }

    private void initDraw() {
	int width = getMeasuredWidth();
	int height = getMeasuredHeight();

	backRect = new Rect(0, 0, width, height);

	circle_y = height / 2;
	centre_right = width - height / 2 - min_space;
	centre_left = height / 2 + min_space;

	if (isOpen) {
	    circle_x = centre_right;
	    alpha = 255;
	   
	} else {
	    circle_x = centre_left;
	    alpha = 0;
	    
	}
    }

    private int getMeasureSize(int defaultSize, int measureSpec) {
	int result = 0;
	int specMode = MeasureSpec.getMode(measureSpec);
	int specSize = MeasureSpec.getSize(measureSpec);
	switch (specMode) {
	case MeasureSpec.EXACTLY:
	    result = measureSpec;
	    break;
	default:
	    result = defaultSize;
	    if (specMode == MeasureSpec.AT_MOST) {
		result = Math.min(defaultSize, specSize);
	    }
	    break;
	}

	return result;
    }

    @Override
    protected void onDraw(Canvas canvas) {
	// TODO Auto-generated method stub
	 textPaint.setTextSize(mTextSize);  
	float raduis = backRect.height() / 2f - min_space;
	mPaint.setColor(Color.GRAY);
	canvas.drawRoundRect(new RectF(backRect), raduis, raduis, mPaint);
	mPaint.setColor(COLOR_THEME);
	mPaint.setAlpha(alpha);
	if (isOpen) {
	    mStr="仅在wifi联网";
            text_x=(canvas.getWidth()-getMeasuredHeight()-min_space)/2-textPaint.measureText(mStr)/2f;
	}else {
	    mStr="流量保护中";
	    text_x=(canvas.getWidth()+getMeasuredHeight()+min_space)/2-textPaint.measureText(mStr)/2f;
	}
	text_y=getMeasuredHeight()/2f-((textPaint.descent() + textPaint.ascent()) / 2);
//	Log.e(TAG, "text_x="+text_x);
	canvas.drawRoundRect(new RectF(backRect), raduis, raduis, mPaint);
	canvas.drawText(mStr, text_x, text_y, textPaint);
	mPaint.setColor(Color.WHITE);
//	Log.e(TAG, "圆心==="+circle_x);
	canvas.drawCircle(circle_x, circle_y, raduis, mPaint);
//	Log.e(TAG, "画布的宽canvas.getWidth()="+canvas.getWidth());
//	Log.e(TAG, "  getMeasuredWidth()="+  getMeasuredWidth());
        
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
	switch (event.getAction()) {
	case MotionEvent.ACTION_DOWN:
	    eventStartX = event.getX();
	    break;
	case MotionEvent.ACTION_MOVE:
	    eventLastX = event.getX();
	    float tempX = eventLastX;
	    tempX = (float) (tempX > centre_right ? centre_right : tempX);
	    tempX = (float) (tempX < centre_left ? centre_left : tempX);
	    if (tempX >= centre_left && tempX <= centre_right) {
		circle_x = tempX;
		circle_y = getMeasuredHeight() / 2;
		alpha = (int) (255 * circle_x /centre_right);
		slide();
	    }
	    break;
	case MotionEvent.ACTION_UP:
	    eventLastX = event.getX();
	    text_y=getMeasuredHeight()/2;
	    if (isOpen) {
		if (eventLastX >getMeasuredWidth() / 2) {
		    circle_x = centre_right;
		    alpha = 255;
		    isOpen=true;
		    slideListener.open();  
		} else {
		    circle_x = centre_left;
		    alpha = 0;
		    isOpen=false;
		    slideListener.close();  
		}
	    } else {
		if (eventLastX < getMeasuredWidth() / 2) {
		    circle_x = centre_left;
		    alpha = 0;
		    isOpen=false;
		    slideListener.close();  
		} else {
		    circle_x = centre_right;
		    alpha = 255;
		    slideListener.open();  
		    isOpen=true;
		}
	    }
	    slide();
	    break;
	}

	return true;
    }

    private void slide() {

	mHander.sleep(1);
    }

    //借鉴aige大神的解决办法,让圆能随着手指的滑动能不停的invalidate()
    private class SlideHander extends Handler {
	@Override
	public void handleMessage(Message msg) {

	    SlideSwitch.this.invalidate();

	}

	public void sleep(long delayMillis) {
	    this.removeMessages(0);
	    sendMessageDelayed(obtainMessage(0), delayMillis);
	}
    }
    public boolean getState() {  
       return isOpen;
    }  
    
}

那个工程不知道怎么上传,有需要的可以留言!(PS:其实这个控件的主要思路是http://blog.csdn.net/chziroy/article/details/44146911这位博主提供的,但是由于我水平有限对于他文中的一些逻辑判断实在是没看懂就自己写了,依然表示非常感谢!)

点击下载源码

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值