Android自定義控件實(shí)現(xiàn)九宮格解鎖
關(guān)于九宮格解鎖,我看了不少博客,但是都感覺很復(fù)雜,可能我的功夫還不到,所以很多東西我不了解,但是我還是打算寫一個(gè)自己的九宮格。我相信我的九宮格大家都能很快的理解,當(dāng)然如果需要實(shí)現(xiàn)更復(fù)雜的功能,需要大家自己接著往深了挖掘。
代碼文件??????
NineGroupView:為九宮格空間組
ToggleView:九宮格中的子View,也就是我們看到的圓形按鈕,我自己定義的ToggleView可能不好看,當(dāng)然大家可以自己定義更加好看的ToggleView。
MarkBean:記錄ToggleView的索引(ChildIndex)以及是否選中的狀態(tài)
PositionUtils:工具類,包含規(guī)劃九個(gè)ToggleView的中心點(diǎn)位置,判斷當(dāng)前觸摸點(diǎn)是否屬于ToggleView中等方法。
NineActivity:測試頁面。
布局規(guī)劃圖
public class PositionUtils { ? ? /** ? ? ?* 判斷觸摸的點(diǎn)是否屬于View中的一點(diǎn) ? ? ?* ? ? ?* @param point ? ?觸摸的點(diǎn) ? ? ?* @param position 目標(biāo)對(duì)象圓形坐標(biāo) ? ? ?* @param outR ? ? 目標(biāo)對(duì)象的外半徑 ? ? ?* @return ? ? ?*/ ? ? public static boolean IsIn(Point point, Point position, int outR) { ? ? ? ? int touchX = point.x; ? ? ? ? int touchY = point.y; ? ? ? ? ? int cx = position.x; ? ? ? ? int cy = position.y; ? ? ? ? ? int distance = (int) Math.sqrt(Math.pow((touchX - cx), 2) + Math.pow((touchY - cy), 2)); ? ? ? ? if (distance <= outR) { ? ? ? ? ? ? return true; ? ? ? ? } else { ? ? ? ? ? ? return false; ? ? ? ? } ? ? } ? ? ? /** ? ? ?* 規(guī)劃 child 的中心位置 ? ? ?* ? ? ?* @param width ? ? ?* @param height ? ? ?* @return ? ? ?*/ ? ? public static List<Point> getNinePoints(int width, int height) { ? ? ? ? List<Point> points = new ArrayList<>(); ? ? ? ? for (int i = 1; i <= 3; i++) { ? ? ? ? ? ? for (int j = 1; j <= 3; j++) { ? ? ? ? ? ? ? ? points.add(getPoint(width, height, 0.25f * j, 0.2f * i + 0.1f)); ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? return points; ? ? } ? ? ? /** ? ? ?* 獲取 ? ? ?* ? ? ?* @param width ?父控件的寬 ? ? ?* @param height 父控件的高 ? ? ?* @param x ? ? ?橫軸方向比例 ? ? ?* @param y ? ? ?縱軸方向的比例 ? ? ?* @return ? ? ?*/ ? ? private static Point getPoint(int width, int height, float x, float y) { ? ? ? ? Point point = new Point(); ? ? ? ? point.x = (int) (width * x); ? ? ? ? point.y = (int) (height * y); ? ? ? ? return point; ? ? } ? }
public class ToggleView extends View { ? ? ? private Paint inPaint; ? ? private Paint outPaint; ? ? private int outColor; ? ? private int inColor; ? ? private int outR; ? ? private int inR; ? ? private boolean isChecked; ? ? ? public int getOutColor() { ? ? ? ? return outColor; ? ? } ? ? ? public void setOutColor(int outColor) { ? ? ? ? this.outColor = outColor; ? ? } ? ? ? public int getInColor() { ? ? ? ? return inColor; ? ? } ? ? ? public void setInColor(int inColor) { ? ? ? ? this.inColor = inColor; ? ? } ? ? ? public int getOutR() { ? ? ? ? return outR; ? ? } ? ? ? public void setOutR(int outR) { ? ? ? ? this.outR = outR; ? ? } ? ? ? public int getInR() { ? ? ? ? return inR; ? ? } ? ? ? public void setInR(int inR) { ? ? ? ? this.inR = inR; ? ? } ? ? ? public boolean isChecked() { ? ? ? ? return isChecked; ? ? } ? ? ? public void setChecked(boolean checked) { ? ? ? ? isChecked = checked; ? ? } ? ? ? public ToggleView(Context context) { ? ? ? ? this(context, null); ? ? } ? ? ? public ToggleView(Context context, @Nullable AttributeSet attrs) { ? ? ? ? this(context, attrs, 0); ? ? } ? ? ? public ToggleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { ? ? ? ? super(context, attrs, defStyleAttr); ? ? ? ? init(context, attrs, defStyleAttr); ? ? } ? ? ? /** ? ? ?* 初始化 ? ? ?*/ ? ? private void init(Context context, AttributeSet attrs, int defStyleAttr) { ? ? ? ? TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ToggleView, defStyleAttr, 0); ? ? ? ? int indexCount = array.getIndexCount(); ? ? ? ? for (int i = 0; i < indexCount; i++) { ? ? ? ? ? ? int attr = array.getIndex(i); ? ? ? ? ? ? switch (attr) { ? ? ? ? ? ? ? ? case R.styleable.ToggleView_InCircleR_T: ? ? ? ? ? ? ? ? ? ? inR = array.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(Dimension.DP, 10, getResources().getDisplayMetrics())); ? ? ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? ? ? case R.styleable.ToggleView_OutCircleR_T: ? ? ? ? ? ? ? ? ? ? outR = array.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(Dimension.DP, 50, getResources().getDisplayMetrics())); ? ? ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? ? ? case R.styleable.ToggleView_InCircleColor_T: ? ? ? ? ? ? ? ? ? ? inColor = array.getColor(attr, 0xff00ffff); ? ? ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? ? ? case R.styleable.ToggleView_OutCircleColor_T: ? ? ? ? ? ? ? ? ? ? outColor = array.getColor(attr, 0xff888888); ? ? ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? inPaint = new Paint(); ? ? ? ? inPaint.setStyle(Paint.Style.FILL_AND_STROKE); ? ? ? ? inPaint.setColor(inColor); ? ? ? ? inPaint.setAntiAlias(true); ? ? ? ? ? outPaint = new Paint(); ? ? ? ? outPaint.setAntiAlias(true); ? ? ? ? outPaint.setStrokeWidth(5); ? ? ? ? outPaint.setStyle(Paint.Style.STROKE); ? ? } ? ? ? ? @Override ? ? protected void onDraw(Canvas canvas) { ? ? ? ? super.onDraw(canvas); ? ? ? ? int cx = getWidth() / 2; ? ? ? ? int cy = getHeight() / 2; ? ? ? ? outPaint.setStyle(Paint.Style.FILL); ? ? ? ? outPaint.setColor(Color.WHITE); ? ? ? ? canvas.drawCircle(cx, cy, outR, outPaint); ? ? ? ? outPaint.setStyle(Paint.Style.STROKE); ? ? ? ? outPaint.setColor(outColor); ? ? ? ? canvas.drawCircle(cx, cy, outR, outPaint); ? ? ? ? canvas.drawCircle(cx, cy, inR, inPaint); ? ? } }
public class NineGroupView extends ViewGroup { ? ? ? private OnFinishListener mListener; ? ? ? public interface OnFinishListener { ? ? ? ? ? public void onFinish(List<Integer> positionSet); ? ? } ? ? ? public void setOnFinishListener(OnFinishListener listener) { ? ? ? ? this.mListener = listener; ? ? } ? ? ? private Paint paint; ? ? private Path path; ? ? private TreeMap<Integer, Boolean> checkedMap; ? ? private List<Integer> checkedINdexSet; ? //用于記錄被選中的序號(hào)排列。 ? ? private List<Point> positionList; ? ? ? private List<Point> childSize = new ArrayList<>(); ? ? ? public NineGroupView(Context context) { ? ? ? ? this(context, null); ? ? } ? ? ? public NineGroupView(Context context, AttributeSet attrs) { ? ? ? ? this(context, attrs, 0); ? ? } ? ? ? public NineGroupView(Context context, AttributeSet attrs, int defStyleAttr) { ? ? ? ? super(context, attrs, defStyleAttr); ? ? ? ? init(); ? ? } ? ? ? public void reset() { ? ? ? ? for (int i = 0; i < 9; i++) { ? ? ? ? ? ? checkedMap.put(i, false); ? ? ? ? } ? ? ? ? checkedINdexSet.clear(); ? ? ? ? IsDownIn = false; ? ? ? ? IsUp = false; ? ? ? ? path.reset(); ? ? ? ? prePoint = new Point(-1, -1); ? ? ? ? currentPoint = new Point(-1, -1); ? ? ? ? invalidate(); ? ? } ? ? ? private void init() { ? ? ? ? checkedMap = new TreeMap<>(); ? ? ? ? for (int i = 0; i < 9; i++) { ? ? ? ? ? ? checkedMap.put(i, false); ? ? ? ? } ? ? ? ? checkedINdexSet = new ArrayList<>(); ? ? ? ? positionList = new ArrayList<>(); ? ? ? ? path = new Path(); ? ? ? ? paint = new Paint(); ? ? ? ? paint.setStrokeWidth(10); ? ? ? ? paint.setAntiAlias(true); ? ? ? ? paint.setColor(Color.RED); ? ? ? ? paint.setStyle(Paint.Style.STROKE); ? ? ? ? //如果該方法在此不調(diào)用的話,那么onDraw()方法將不被調(diào)用,那么就無法完成連接線的繪制 ? ? ? ? setWillNotDraw(false); ? ? } ? ? ? @Override ? ? protected void onLayout(boolean b, int left, int top, int right, int bottom) { ? ? ? ? int height = getMeasuredHeight(); ? ? ? ? int width = getMeasuredWidth(); ? ? ? ? positionList = PositionUtils.getNinePoints(width, height); ? ? ? ? int childCount = getChildCount(); ? ? ? ? for (int i = 0; i < childCount; i++) { ? ? ? ? ? ? View child = getChildAt(i); ? ? ? ? ? ? Point size = childSize.get(i); ? ? ? ? ? ? Point position = positionList.get(i); ? ? ? ? ? ? int cLeft = position.x - size.x; ? ? ? ? ? ? int cTop = position.y - size.y; ? ? ? ? ? ? int cRight = position.x + size.x; ? ? ? ? ? ? int cBottom = position.y + size.y; ? ? ? ? ? ? child.layout(cLeft, cTop, cRight, cBottom); ? ? ? ? } ? ? } ? ? ? @Override ? ? protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { ? ? ? ? int childCount = getChildCount(); ? ? ? ? for (int i = 0; i < childCount; i++) { ? ? ? ? ? ? View child = getChildAt(i); ? ? ? ? ? ? measureChild(child, widthMeasureSpec, heightMeasureSpec); ? ? ? ? ? ? Point point = new Point(); ? ? ? ? ? ? point.x = child.getMeasuredWidth(); ? ? ? ? ? ? point.y = child.getMeasuredHeight(); ? ? ? ? ? ? childSize.add(point); ? ? ? ? } ? ? ? ? setMeasuredDimension(widthMeasureSpec, heightMeasureSpec); ? ? } ? ? ? private boolean IsDownIn = false; ? ? private boolean IsUp = false; ? ? ? private Point prePoint = new Point(-1, -1); ? ? private Point currentPoint = new Point(-1, -1); ? ? ? @Override ? ? public boolean onTouchEvent(MotionEvent event) { ? ? ? ? int action = event.getAction(); ? ? ? ? int currentX = (int) event.getX(); ? ? ? ? int currentY = (int) event.getY(); ? ? ? ? switch (action) { ? ? ? ? ? ? case MotionEvent.ACTION_DOWN: { ? ? ? ? ? ? ? ? if (IsUp) { ? ? ? ? ? ? ? ? ? ? return true; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? MarkBean bean = isInToggle(new Point(currentX, currentY)); ? ? ? ? ? ? ? ? if (bean != null) { ? ? ? ? ? ? ? ? ? ? IsDownIn = true; ? ? ? ? ? ? ? ? ? ? prePoint = positionList.get(bean.getIndex()); ? ? ? ? ? ? ? ? ? ? path.moveTo(prePoint.x, prePoint.y); ? ? ? ? ? ? ? ? ? ? invalidate(); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? ? ? break; ? ? ? ? ? ? case MotionEvent.ACTION_UP: ? ? ? ? ? ? ? ? IsUp = true; ? ? ? ? ? ? ? ? if (IsDownIn) { ? ? ? ? ? ? ? ? ? ? currentPoint = prePoint; ? ? ? ? ? ? ? ? ? ? IsDownIn = false; ? ? ? ? ? ? ? ? ? ? invalidate(); ? ? ? ? ? ? ? ? ? ? if (mListener != null) { ? ? ? ? ? ? ? ? ? ? ? ? mListener.onFinish(checkedINdexSet); ? ? ? ? ? ? ? ? ? ? ? ? reset(); ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? case MotionEvent.ACTION_MOVE: { ? ? ? ? ? ? ? ? if (IsDownIn) { ? ? ? ? ? ? ? ? ? ? if (!IsUp) { ? ? ? ? ? ? ? ? ? ? ? ? MarkBean bean = isInToggle(new Point(currentX, currentY)); ? ? ? ? ? ? ? ? ? ? ? ? if (bean != null) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? int index = bean.getIndex(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? currentPoint = positionList.get(index); ? ? ? ? ? ? ? ? ? ? ? ? ? ? path.lineTo(currentPoint.x, currentPoint.y); ? ? ? ? ? ? ? ? ? ? ? ? ? ? invalidate(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? prePoint = currentPoint; ? ? ? ? ? ? ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? ? ? ? ? ? ? currentPoint = new Point(currentX, currentY); ? ? ? ? ? ? ? ? ? ? ? ? ? ? invalidate(); ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? ? ? if (!IsUp) { ? ? ? ? ? ? ? ? ? ? ? ? MarkBean bean = isInToggle(new Point(currentX, currentY)); ? ? ? ? ? ? ? ? ? ? ? ? if (bean != null) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? Point position = positionList.get(bean.getIndex()); ? ? ? ? ? ? ? ? ? ? ? ? ? ? prePoint = position; ? ? ? ? ? ? ? ? ? ? ? ? ? ? path.moveTo(position.x, position.y); ? ? ? ? ? ? ? ? ? ? ? ? ? ? IsDownIn = true; ? ? ? ? ? ? ? ? ? ? ? ? ? ? invalidate(); ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? ? ? break; ? ? ? ? ? ? case MotionEvent.ACTION_CANCEL: ? ? ? ? ? ? ? ? ? break; ? ? ? ? } ? ? ? ? return true; ? ? } ? ? ? private MarkBean isInToggle(Point point) { ? ? ? ? MarkBean bean = new MarkBean(); ? ? ? ? int childCount = getChildCount(); ? ? ? ? for (int i = 0; i < childCount; i++) { ? ? ? ? ? ? Point position = positionList.get(i); ? ? ? ? ? ? ToggleView child = (ToggleView) getChildAt(i); ? ? ? ? ? ? if (PositionUtils.IsIn(point, position, child.getOutR())) { ? ? ? ? ? ? ? ? if (!checkedMap.get(i)) { ? ? ? ? ? ? ? ? ? ? checkedMap.put(i, true); ? ? ? ? ? ? ? ? ? ? checkedINdexSet.add(i); ? ? ? ? ? ? ? ? ? ? bean.setIndex(i); ? ? ? ? ? ? ? ? ? ? bean.setCheck(true); ? ? ? ? ? ? ? ? ? ? return bean; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? return null; ? ? } ? ? ? @Override ? ? protected void onDraw(Canvas canvas) { ? ? ? ? canvas.drawPath(path, paint); ? ? ? ? if (prePoint.x != -1 && prePoint.y != -1 && currentPoint.x != -1 && currentPoint.y != -1) { ? ? ? ? ? ? canvas.drawLine(prePoint.x, prePoint.y, currentPoint.x, currentPoint.y, paint); ? ? ? ? } ? ? ? ? super.onDraw(canvas); ? ? } }
代碼總是最直接的引導(dǎo),我看博客最喜歡的是研究代碼,當(dāng)然如果代碼中有一些講解就更好了。
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- android 九宮格滑動(dòng)解鎖開機(jī)實(shí)例源碼學(xué)習(xí)
- 輕松實(shí)現(xiàn)Android自定義九宮格圖案解鎖
- Android實(shí)現(xiàn)九宮格解鎖
- 輕松實(shí)現(xiàn)安卓(Android)九宮格解鎖
- Android實(shí)現(xiàn)九宮格解鎖的實(shí)例代碼
- 使用Android自定義控件實(shí)現(xiàn)滑動(dòng)解鎖九宮格
- Android 仿小米鎖屏實(shí)現(xiàn)九宮格解鎖功能(無需圖片資源)
- Android自定義控件實(shí)現(xiàn)九宮格解鎖功能
- Android自定義View九宮格手勢密碼解鎖
- Android實(shí)現(xiàn)九宮格手勢解鎖
相關(guān)文章
Android SeekBar實(shí)現(xiàn)滑動(dòng)條效果
這篇文章主要為大家詳細(xì)介紹了Android SeekBar實(shí)現(xiàn)滑動(dòng)條效果,可以改變并顯示當(dāng)前進(jìn)度的拖動(dòng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07Android從系統(tǒng)Gallery獲取圖片具體實(shí)現(xiàn)
這篇文章主要介紹了Android從系統(tǒng)Gallery獲取圖片具體實(shí)現(xiàn),有需要的朋友可以參考一下2013-12-12???????Android?H5通用容器架構(gòu)設(shè)計(jì)詳解
這篇文章主要介紹了???????Android?H5通用容器架構(gòu)設(shè)計(jì)詳解,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09Android BroadcastReceiver實(shí)現(xiàn)網(wǎng)絡(luò)狀態(tài)實(shí)時(shí)監(jiān)聽
這篇文章主要為大家詳細(xì)介紹了Android BroadcastReceiver實(shí)現(xiàn)網(wǎng)絡(luò)狀態(tài)實(shí)時(shí)監(jiān)聽,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05Android使用OkHttp請(qǐng)求自簽名的https網(wǎng)站的示例
本篇文章主要介紹了Android使用OkHttp請(qǐng)求自簽名的https網(wǎng)站的示例,非常具有實(shí)用價(jià)值,需要的朋友可以參考下、2017-09-09