标签:

<resources<!-- 声名属性集的名称 --><declare-styleable name="MyToggleBtn"><!-- 声名一个属性 name是my_background 类型为 引用类型 引用资源ID --><attr name="my_background" format="reference" /><!-- 声名一个属性 name是my_slide_btn 类型为 引用类型 引用资源ID --><attr name="my_slide_btn" format="reference" /><!-- 声名一个属性 name是curr_state 类型为 boolean 类型--><attr name="curr_state" format="boolean" /></declare-styleable></resources>
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:heima="http://schemas.android.com/apk/res/com.itheima.togglebtn28"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity" ><com.itheima.togglebtn28.MyToggleButtonandroid:id="@+id/my_toggle_btn"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerHorizontal="true"android:layout_centerVertical="true"heima:my_background="@drawable/switch_background"heima:my_slide_btn="@drawable/slide_button"heima:curr_state="false"testAttrs="@drawable/ic_launcher"/></RelativeLayout>
public class MyToggleButton extends View implements OnClickListener{/*** 做为背景的图片*/private Bitmap backgroundBitmap;/*** 可以滑动的图片*/private Bitmap slideBtn;private Paint paint;/*** 滑动按钮的左边届*/private float slideBtn_left;/*** 背景图的资源ID*/private int backgroundId;/*** 滑动图片的资源ID*/private int slideBtnId;/*** 在代码里面创建对象的时候,使用此构造方法*/public MyToggleButton(Context context) {super(context);// TODO Auto-generated constructor stub}/*** 在布局文件中声名的view,创建时由系统自动调用。* @param context 上下文对象* @param attrs 属性集*/public MyToggleButton(Context context, AttributeSet attrs) {super(context, attrs);//无命名空间测试String testAttrs = attrs.getAttributeValue(null, "testAttrs");System.out.println("testAttrs===:"+testAttrs);//获得自定义的属性TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyToggleBtn);int N = ta.getIndexCount();for (int i = 0; i < N; i++) {/** 获得某个属性的ID值*/int itemId = ta.getIndex(i);switch (itemId) {case R.styleable.MyToggleBtn_curr_state:currState = ta.getBoolean(itemId, false);break;case R.styleable.MyToggleBtn_my_background:backgroundId = ta.getResourceId(itemId, -1);if(backgroundId == -1){throw new RuntimeException("请设置背景图片");}backgroundBitmap = BitmapFactory.decodeResource(getResources(), backgroundId);break;case R.styleable.MyToggleBtn_my_slide_btn:slideBtnId = ta.getResourceId(itemId, -1);slideBtn = BitmapFactory.decodeResource(getResources(), slideBtnId);break;default:break;}}initView();}/*** 初始化*/private void initView() {//初始化图片// backgroundBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.switch_background);// slideBtn = BitmapFactory.decodeResource(getResources(), R.drawable.slide_button);//初始化 画笔paint = new Paint();paint.setAntiAlias(true); // 打开抗矩齿//添加onclick事件监听setOnClickListener(this);flushState();}/** view 对象显示的屏幕上,有几个重要步骤:* 1、构造方法 创建 对象。* 2、测量view的大小。 onMeasure(int,int);* 3、确定view的位置 ,view自身有一些建议权,决定权在 父view手中。 onLayout();* 4、绘制 view 的内容 。 onDraw(Canvas)*/@Override/*** 测量尺寸时的回调方法*/protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// super.onMeasure(widthMeasureSpec, heightMeasureSpec);/*** 设置当前view的大小* width :view的宽度* height :view的高度 (单位:像素)*/setMeasuredDimension(backgroundBitmap.getWidth(),backgroundBitmap.getHeight());}//确定位置的时候调用此方法//自定义view的时候,作用不大// @Override// protected void onLayout(boolean changed, int left, int top, int right,// int bottom) {// super.onLayout(changed, left, top, right, bottom);// }/*** 当前开关的状态* true 为开??*/private boolean currState = false;@Override/*** 绘制当前view的内容*/protected void onDraw(Canvas canvas) {// super.onDraw(canvas);// 绘制 背景/** backgroundBitmap 要绘制的图片* left 图片的左边届* top 图片的上边届* paint 绘制图片要使用的画笔*/canvas.drawBitmap(backgroundBitmap, 0, 0, paint);//绘制 可滑动的按钮canvas.drawBitmap(slideBtn, slideBtn_left, 0, paint);}/*** 判断是否发生拖动,* 如果拖动了,就不再响应 onclick 事件**/private boolean isDrag = false;@Override/*** onclick 事件在View.onTouchEvent 中被解析。* 系统对onclick 事件的解析,过于简陋,只要有down 事件 up 事件,系统即认为 发生了click 事件**/public void onClick(View v) {/** 如果没有拖动,才执行改变状态的动作*/if(!isDrag){currState = !currState;flushState();}}/*** down 事件时的x值*/private int firstX;/*** touch 事件的上一个x值*/private int lastX;@Overridepublic boolean onTouchEvent(MotionEvent event) {super.onTouchEvent(event);switch (event.getAction()) {case MotionEvent.ACTION_DOWN:firstX = lastX =(int) event.getX();isDrag = false;break;case MotionEvent.ACTION_MOVE://判断是否发生拖动if(Math.abs(event.getX()-firstX)>5){isDrag = true;}//计算 手指在屏幕上移动的距离int dis = (int) (event.getX() - lastX);//将本次的位置 设置给lastXlastX = (int) event.getX();//根据手指移动的距离,改变slideBtn_left 的值slideBtn_left = slideBtn_left+dis;break;case MotionEvent.ACTION_UP://在发生拖动的情况下,根据最后的位置,判断当前开关的状态if (isDrag) {int maxLeft = backgroundBitmap.getWidth() - slideBtn.getWidth(); // slideBtn// 左边届最大值/** 根据 slideBtn_left 判断,当前应是什么状态*/if (slideBtn_left > maxLeft / 2) { // 此时应为 打开的状态currState = true;} else {currState = false;}flushState();}break;}flushView();return true; //将事件消费掉}/*** 刷新当前状态*/private void flushState() {if(currState){slideBtn_left = backgroundBitmap.getWidth()-slideBtn.getWidth();}else{slideBtn_left = 0;}flushView();}/*** 刷新当前视力*/private void flushView() {/** 对 slideBtn_left 的值进行判断 ,确保其在合理的位置 即 0<=slideBtn_left <= maxLeft**/int maxLeft = backgroundBitmap.getWidth()-slideBtn.getWidth(); // slideBtn 左边届最大值//确保 slideBtn_left >= 0slideBtn_left = (slideBtn_left>0)?slideBtn_left:0;//确保 slideBtn_left <=maxLeftslideBtn_left = (slideBtn_left<maxLeft)?slideBtn_left:maxLeft;/** 刷新当前视图 导致 执行onDraw执行*/invalidate();}}

public class MyRring extends View{/*** 圆环圆心的X坐标*/private int cx;/*** 圆环圆心的Y坐标*/private int cy;private Paint paint;/*** 圆环的半径*/private float radius;/*** 线条的厚度*/private float strokeWidth;public MyRring(Context context, AttributeSet attrs) {super(context, attrs);initView();}private void initView() {//初始化paintpaint = new Paint();paint.setAntiAlias(true); // 抗矩齿paint.setColor(Color.RED);paint.setStyle(Style.STROKE); //刻画,画线条paint.setStrokeWidth(strokeWidth); //设置条线的厚度paint.setAlpha(255); //设置透明度 ,0--255 0代表完全透明//this.radius =0;strokeWidth = 0;}@Override/*** 绘制我们的内容*/protected void onDraw(Canvas canvas) {super.onDraw(canvas);/*** 绘制圆环*/canvas.drawCircle(cx, cy, radius, paint);}@Overridepublic boolean onTouchEvent(MotionEvent event) {super.onTouchEvent(event);switch (event.getAction()) {case MotionEvent.ACTION_DOWN: // 点击,获得圆环的中心cx = (int) event.getX();cy = (int) event.getY();//初始化画笔initView();handler.sendEmptyMessage(0);break;}return true;}/** 刷新状态*/private void flushState() {this.radius+=10;this.strokeWidth = radius/4;paint.setStrokeWidth(strokeWidth);int nextAlpha = paint.getAlpha()-20;if(nextAlpha<=20){nextAlpha = 0;}paint.setAlpha(nextAlpha);}private Handler handler = new Handler(){public void handleMessage(android.os.Message msg) {flushState();// 刷新页面 执行onDraw()方法invalidate();if(paint.getAlpha() !=0){handler.sendEmptyMessageDelayed(0, 100);}};};@Override/*** 大小的测量按系统的默认规则*/protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);}}
public class MyRing extends View{/*** 圆心的X坐标*/private float cx;/*** 圆心的Y坐标*/private float cy;/*** 圆环半径*/private float radius = 0;/*** 默认画笔*/private Paint paint;protected boolean isRunning = false;public MyRing(Context context, AttributeSet attrs) {super(context, attrs);initView();}private void initView() {radius = 0;paint = new Paint();paint.setAntiAlias(true);paint.setStyle(Style.STROKE);paint.setStrokeWidth(radius/4);paint.setColor(Color.GREEN);paint.setAlpha(255);}/*** 执行动画*/private void startAnim() {isRunning = true;handler.sendEmptyMessageDelayed(0, 50);}@Overrideprotected void onAttachedToWindow() {super.onAttachedToWindow();// startAnim() ;}@Overrideprotected void onDetachedFromWindow() {super.onDetachedFromWindow();isRunning = false;}private Handler handler = new Handler(){public void handleMessage(android.os.Message msg) {// 设置透明度int alpha = paint.getAlpha();if (alpha == 0) {isRunning = false;}// alpha -= 10;//// if (alpha <= 10) {// alpha = 0;// }alpha = Math.max(0, alpha-10);paint.setAlpha(alpha);Log.i("leo", "" + alpha);// 设置半径radius += 5;paint.setStrokeWidth(radius / 3);invalidate();if (isRunning) {handler.sendEmptyMessageDelayed(0, 50);}};};@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);// setMeasuredDimension(200, 200);}@Overrideprotected void onLayout(boolean changed, int left, int top, int right,int bottom) {if(changed){cx = getWidth()/2;cy = getHeight()/2;}}@Overrideprotected void onDraw(Canvas canvas) {canvas.drawCircle(cx, cy, radius, paint);}@Overridepublic boolean onTouchEvent(MotionEvent event) {super.onTouchEvent(event);if(event.getAction() == MotionEvent.ACTION_DOWN){cx = event.getX();cy = event.getY();initView();startAnim();}return true;}}
public class MyRingSimple extends View{/*** 圆心的X坐标*/private float cx;/*** 圆心的Y坐标*/private float cy;/*** 圆环半径*/private float radius = 0;/*** 默认画笔*/private Paint paint;protected boolean isRunning = false;private Paint lPaint;public MyRingSimple(Context context, AttributeSet attrs) {super(context, attrs);initView();}private void initView() {radius = 50;paint = new Paint();paint.setAntiAlias(true);paint.setStyle(Style.STROKE);paint.setStrokeWidth(radius/4);paint.setColor(Color.GREEN);paint.setAlpha(255);lPaint = new Paint();lPaint.setAntiAlias(true);lPaint.setStyle(Style.STROKE);lPaint.setColor(Color.GREEN);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);setMeasuredDimension(200, 200);}@Overrideprotected void onLayout(boolean changed, int left, int top, int right,int bottom) {if(changed){cx = getWidth()/2;cy = getHeight()/2;}}@Overrideprotected void onDraw(Canvas canvas) {for (int i = 10; i < getWidth(); i=i+20) {canvas.drawLine(0, i, getWidth(), i, lPaint);canvas.drawLine(i, 0, i,getHeight(), lPaint);}paint.setColor(Color.GREEN);canvas.translate(-20, -20);canvas.drawCircle(cx, cy, radius, paint);}}
/*** 水波纹效果* @author leo**/public class MyRingWave extends View{/*** 二个相临波浪中心点的最小距离*/private static final int DIS_SOLP = 13;protected boolean isRunning = false;private ArrayList<Wave> wList;public MyRingWave(Context context, AttributeSet attrs) {super(context, attrs);wList = new ArrayList<MyRingWave.Wave>();}private Handler handler = new Handler(){public void handleMessage(android.os.Message msg) {//刷新数据flushData();//刷新页面invalidate();//循环动画if (isRunning) {handler.sendEmptyMessageDelayed(0, 50);}};};@Overrideprotected void onDraw(Canvas canvas) {for (int i = 0; i < wList.size(); i++) {Wave wave = wList.get(i);canvas.drawCircle(wave.cx, wave.cy, wave.r, wave.p);}}@Overridepublic boolean onTouchEvent(MotionEvent event) {super.onTouchEvent(event);switch (event.getAction()) {case MotionEvent.ACTION_DOWN:case MotionEvent.ACTION_MOVE:int x = (int) event.getX();int y = (int) event.getY();addPoint(x,y);break;default:break;}return true;}/*** 添加新的波浪中心点* @param x* @param y*/private void addPoint(int x, int y) {if(wList.size() == 0){addPoint2List(x,y);/** 第一次启动动画*/isRunning = true;handler.sendEmptyMessage(0);}else{Wave w = wList.get(wList.size()-1);if(Math.abs(w.cx - x)>DIS_SOLP || Math.abs(w.cy-y)>DIS_SOLP){addPoint2List(x,y);}};}/*** 添加新的波浪* @param x* @param y*/private void addPoint2List(int x, int y) {Wave w = new Wave();w.cx = x;w.cy=y;Paint pa=new Paint();pa.setColor(colors[(int)(Math.random()*4)]);pa.setAntiAlias(true);pa.setStyle(Style.STROKE);w.p = pa;wList.add(w);}private int [] colors = new int[]{Color.BLUE,Color.RED,Color.YELLOW,Color.GREEN};/*** 刷新数据*/private void flushData() {for (int i = 0; i < wList.size(); i++) {Wave w = wList.get(i);//如果透明度为 0 从集合中删除int alpha = w.p.getAlpha();if(alpha == 0){wList.remove(i); //删除i 以后,i的值应该再减1 否则会漏掉一个对象,不过,在此处影响不大,效果上看不出来。continue;}alpha-=5;if(alpha<5){alpha =0;}//降低透明度w.p.setAlpha(alpha);//扩大半径w.r = w.r+3;//设置半径厚度w.p.setStrokeWidth(w.r/3);}/** 如果集合被清空,就停止刷新动画*/if(wList.size() == 0){isRunning = false;}}/*** 定义一个波浪* @author leo*/private class Wave {//圆心int cx;int cy;//画笔Paint p;//半径int r;}}
标签:
原文地址:http://www.cnblogs.com/liuyu0529/p/5021883.html