android仿IOS選擇(switch)開關
阿新 • • 發佈:2018-12-30
最近看見很多應用用這種仿IOS的開關控制元件,最近專案組也有要用到這個控制元件的需要,實際上最簡單的方法是,直接讓UI提供兩張圖片就可以了,分別代表開啟和關閉的狀態,但是UI實在是不給力,圖片遲遲不到,所以,作為一個勤奮好學,自力更生的android程式設計師來說,好吧,果斷自己自定義一個。
其實,要實現這個功能,也不是很難,可以說非常easy。就是通過canvas畫一個底層橢圓形的矩形,然後上面畫一個開關的小圓圈,底層顏色和小圓圈所處位置根據開關狀態不同顯示。好了,先上圖。
娃
最後效果圖就是這樣的。程式碼如下:
package com.lyq.customSwitch; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.util.AttributeSet; import android.view.View; import android.view.View.OnClickListener; /** * 仿IOS選擇開關 * @author mufeng * */ public class Switch extends View implements OnClickListener{ private Context mContext; private Paint mPaint; private float width,height; private boolean isOpen=true; private RectF oval; public Switch(Context context) { super(context); init(context); } public Switch(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public Switch(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } public Switch(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(context); } private void init(Context context) { mContext=context; //設定寬高 width=DensityUtils.dip2px(mContext, 80); height=width/2; mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); setOnClickListener(this); oval = new RectF(0, 0, width, height); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //根據控制元件當前狀態設定畫筆顏色 if(isOpen){ mPaint.setColor(getResources().getColor(R.color.select)); }else{ mPaint.setColor(Color.GRAY); } mPaint.setStyle(Paint.Style.FILL);// 充滿 //畫底層圓角矩形 canvas.drawRoundRect(oval,height/2 , width/4, mPaint);// 第二個引數是x半徑,第三個引數是y半徑 //畫開關圓圈 將畫筆顏色設為白色 mPaint.setColor(Color.WHITE); //根據控制元件當前狀態判斷將圓圈畫在左邊還是右邊 if(isOpen){ canvas.drawCircle(width/4*3, height/2, height/2-DensityUtils.dip2px(mContext, 2), mPaint); }else{ canvas.drawCircle(width/4, height/2, height/2-DensityUtils.dip2px(mContext, 2), mPaint); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //重新測量控制元件的大小,主要在控制元件寬高屬性設定為wrap_content時,將控制元件大小設定為實際大小 setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec)); } //測量寬度 private int measureWidth(int measureSpec) { int result = 0; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) { result = specSize; } else { result = (int) DensityUtils.dip2px(mContext, 80) + getPaddingLeft() + getPaddingRight(); if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } } return result; } //測量高度 private int measureHeight(int measureSpec) { int result = 0; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) { result = specSize; } else { result = (int) DensityUtils.dip2px(mContext, 80)/2 + getPaddingTop() + getPaddingBottom(); if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } } return result; } /** * 點選切換isOpen值,呼叫postInvalidate重繪view,可用於非同步執行緒 */ @Override public void onClick(View view) { isOpen=!isOpen; postInvalidate(); } /** * 開啟控制元件開關 */ public void open(){ if(!isOpen){ isOpen=true; postInvalidate(); } } /** * 關閉控制元件開關 */ public void close(){ if(isOpen){ isOpen=false; postInvalidate(); } } /** * 獲取控制元件狀態 * @return */ public boolean isOpen(){ return isOpen; } }
程式碼中各個方法都註釋的比較詳細,具體的我就不介紹了。最後附上專案原始碼。