Android自定義View實(shí)現(xiàn)遙控器按鈕
本文實(shí)例為大家分享了Android自定義View實(shí)現(xiàn)遙控器按鈕的具體代碼,供大家參考,具體內(nèi)容如下
效果圖:
原理:
- onSizeChanged拿到控件寬高,進(jìn)行path和region的計(jì)算(此處,path和region的坐標(biāo)值都是以viewWidth/2,viewHeight/2為坐標(biāo)原點(diǎn)進(jìn)行計(jì)算的)
- 畫布平移,繪制5個(gè)path
- 點(diǎn)擊事件,判斷是否處于相應(yīng)的region區(qū)域內(nèi),進(jìn)行控件的重繪
- 點(diǎn)擊事件motionEvent的原始坐標(biāo)(getX和getY),是以viewParent的左上角為坐標(biāo)原點(diǎn)的,需要經(jīng)過(guò)matrix轉(zhuǎn)換成以控件中心點(diǎn)為原點(diǎn)的坐標(biāo)體系。
Region區(qū)域,paint的style設(shè)置為stroke模式,遍歷繪制
mPaint.setColor(Color.RED); RegionIterator iterator = new RegionIterator(topRegion); ?Rect r = new Rect(); ?while (iterator.next(r)) { ? ? ? canvas.drawRect(r, mPaint); ?}
源碼:
public class RemoteControlMenu extends View { ? ? private int mWidth; ? ? private int mHeight; ? ? private RectF bigRectF; ? ? private int bigRadius; ? ? private RectF smallRectF; ? ? private int smallRadius; ? ? private int padding = 20; ? ? private int sweepAngel = 80; ? ? private int offsetAngel; ? ? @TouchArea ? ? private int mTouchArea = TouchArea.INVALID; ? ? private Paint mPaint; ? ? private Region topRegion, bottomRegion, leftRegion, rightRegion, centerRegion, globalRegion; ? ? private Path topPath, bottomPath, leftPath, rightPath, centerPath, selectedPath; ? ? Matrix mMapMatrix; ? ? private int unselectedColor = 0xff4c5165; ? ? private int selectedColor = 0xffdd9181; ? ? private boolean isSelected = false; ? ? public RemoteControlMenu(Context context) { ? ? ? ? this(context, null); ? ? } ? ? public RemoteControlMenu(Context context, @Nullable AttributeSet attrs) { ? ? ? ? this(context, attrs, 0); ? ? } ? ? public RemoteControlMenu(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { ? ? ? ? super(context, attrs, defStyleAttr); ? ? ? ? mPaint = new Paint(); ? ? ? ? mPaint.setAntiAlias(true); ? ? ? ? mPaint.setStyle(Paint.Style.FILL); ? ? ? ? mPaint.setStrokeWidth(4); ? ? ? ? mPaint.setColor(unselectedColor); ? ? ? ? offsetAngel = (360 - sweepAngel * 4) / 4; ? ? ? ? bigRectF = new RectF(); ? ? ? ? smallRectF = new RectF(); ? ? ? ? topRegion = new Region(); ? ? ? ? bottomRegion = new Region(); ? ? ? ? leftRegion = new Region(); ? ? ? ? rightRegion = new Region(); ? ? ? ? centerRegion = new Region(); ? ? ? ? globalRegion = new Region(); ? ? ? ? topPath = new Path(); ? ? ? ? bottomPath = new Path(); ? ? ? ? leftPath = new Path(); ? ? ? ? rightPath = new Path(); ? ? ? ? centerPath = new Path(); ? ? ? ? mMapMatrix = new Matrix(); ? ? } ? ? @Retention(RetentionPolicy.SOURCE) ? ? @IntDef({TouchArea.LEFT, TouchArea.TOP, TouchArea.RIGHT, TouchArea.BOTTOM, ? ? ? ? ? ? TouchArea.CENTER, TouchArea.INVALID}) ? ? private @interface TouchArea { ? ? ? ? int LEFT = 1; ? ? ? ? int TOP = 2; ? ? ? ? int RIGHT = 3; ? ? ? ? int BOTTOM = 4; ? ? ? ? int CENTER = 5; ? ? ? ? int INVALID = 0; ? ? } ? ? @Override ? ? public boolean onTouchEvent(MotionEvent event) { ? ? ? ? float[] pts = new float[2]; ? ? ? ? pts[0] = event.getX(); ? ? ? ? pts[1] = event.getY(); ? ? ? ? Log.d("zhen", "原始觸摸位置:" + Arrays.toString(pts) + " mMapMatrix: " + mMapMatrix); ? ? ? ? mMapMatrix.mapPoints(pts); ? ? ? ? int x = (int) pts[0]; ? ? ? ? int y = (int) pts[1]; ? ? ? ? Log.w("zhen", "轉(zhuǎn)換后的觸摸位置:" + Arrays.toString(pts) + " mMapMatrix: " + mMapMatrix); ? ? ? ? int touchArea = TouchArea.INVALID; ? ? ? ? switch (event.getAction()) { ? ? ? ? ? ? case MotionEvent.ACTION_UP: ? ? ? ? ? ? ? ? if (leftRegion.contains(x, y)) { ? ? ? ? ? ? ? ? ? ? touchArea = TouchArea.LEFT; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? if (topRegion.contains(x, y)) { ? ? ? ? ? ? ? ? ? ? touchArea = TouchArea.TOP; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? if (rightRegion.contains(x, y)) { ? ? ? ? ? ? ? ? ? ? touchArea = TouchArea.RIGHT; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? if (bottomRegion.contains(x, y)) { ? ? ? ? ? ? ? ? ? ? touchArea = TouchArea.BOTTOM; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? if (centerRegion.contains(x, y)) { ? ? ? ? ? ? ? ? ? ? touchArea = TouchArea.CENTER; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? if (touchArea == TouchArea.INVALID) { ? ? ? ? ? ? ? ? ? ? mTouchArea = touchArea; ? ? ? ? ? ? ? ? ? ? Log.w("zhen", "點(diǎn)擊outside"); ? ? ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? ? ? if (mTouchArea == touchArea) { ? ? ? ? ? ? ? ? ? ? ? ? //取消選中 ? ? ? ? ? ? ? ? ? ? ? ? isSelected = false; ? ? ? ? ? ? ? ? ? ? ? ? mTouchArea = TouchArea.INVALID; ? ? ? ? ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? ? ? ? ? //選中 ? ? ? ? ? ? ? ? ? ? ? ? isSelected = true; ? ? ? ? ? ? ? ? ? ? ? ? mTouchArea = touchArea; ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? Log.w("zhen", "按鈕狀態(tài) mTouchArea " + mTouchArea + " isSelected: " + isSelected); ? ? ? ? ? ? ? ? ? ? if (mListener != null) { ? ? ? ? ? ? ? ? ? ? ? ? mListener.onMenuClicked(mTouchArea, isSelected); ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? invalidate(); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? break; ? ? ? ? } ? ? ? ? return true; ? ? } ? ? @Override ? ? protected void onSizeChanged(int w, int h, int oldw, int oldh) { ? ? ? ? super.onSizeChanged(w, h, oldw, oldh); ? ? ? ? mWidth = w; ? ? ? ? mHeight = h; ? ? ? ? //大圓 ? ? ? ? bigRadius = (Math.min(mWidth, mHeight) - 250) / 2; ? ? ? ? bigRectF.set(-bigRadius, -bigRadius, bigRadius, bigRadius); ? ? ? ? //小圓 ? ? ? ? smallRadius = (bigRadius - padding) / 2; ? ? ? ? smallRectF.set(-smallRadius - padding, -smallRadius - padding, ? ? ? ? ? ? ? ? smallRadius + padding, smallRadius + padding); ? ? ? ? mMapMatrix.reset(); ? ? ? ? globalRegion.set(-mWidth / 2, -mHeight / 2, mWidth / 2, mHeight / 2); ? ? ? ? centerPath.addCircle(0, 0, smallRadius, Path.Direction.CW); ? ? ? ? centerRegion.setPath(centerPath, globalRegion); ? ? ? ? float startAngel = -sweepAngel / 2f; ? ? ? ? rightPath.addArc(bigRectF, startAngel, sweepAngel + 4); ? ? ? ? startAngel += sweepAngel; ? ? ? ? rightPath.arcTo(smallRectF, startAngel, -sweepAngel); ? ? ? ? rightPath.close(); ? ? ? ? rightRegion.setPath(rightPath, globalRegion); ? ? ? ? startAngel += offsetAngel; ? ? ? ? bottomPath.addArc(bigRectF, startAngel, sweepAngel + 4); ? ? ? ? startAngel += sweepAngel; ? ? ? ? bottomPath.arcTo(smallRectF, startAngel, -sweepAngel); ? ? ? ? bottomPath.close(); ? ? ? ? bottomRegion.setPath(bottomPath, globalRegion); ? ? ? ? startAngel += offsetAngel; ? ? ? ? leftPath.addArc(bigRectF, startAngel, sweepAngel + 4); ? ? ? ? startAngel += sweepAngel; ? ? ? ? leftPath.arcTo(smallRectF, startAngel, -sweepAngel); ? ? ? ? leftPath.close(); ? ? ? ? leftRegion.setPath(leftPath, globalRegion); ? ? ? ? startAngel += offsetAngel; ? ? ? ? topPath.addArc(bigRectF, startAngel, sweepAngel + 4); ? ? ? ? startAngel += sweepAngel; ? ? ? ? topPath.arcTo(smallRectF, startAngel, -sweepAngel); ? ? ? ? topPath.close(); ? ? ? ? topRegion.setPath(topPath, globalRegion); ? ? ? ? Log.d("zhen", "globalRegion: " + globalRegion); ? ? ? ? Log.d("zhen", "globalRegion: " + globalRegion); ? ? ? ? Log.d("zhen", "leftRegion: " + leftRegion); ? ? ? ? Log.d("zhen", "topRegion: " + topRegion); ? ? ? ? Log.d("zhen", "rightRegion: " + rightRegion); ? ? ? ? Log.d("zhen", "bottomRegion: " + bottomRegion); ? ? ? ? Log.d("zhen", "centerRegion: " + centerRegion); ? ? } ? ? @Override ? ? protected void onDraw(Canvas canvas) { ? ? ? ? super.onDraw(canvas); ? ? ? ? canvas.translate(mWidth / 2, mHeight / 2); ? ? ? ? // 獲取測(cè)量矩陣(逆矩陣) ? ? ? ? if (mMapMatrix.isIdentity()) { ? ? ? ? ? ? canvas.getMatrix().invert(mMapMatrix); ? ? ? ? } ? ? ? ? mPaint.setColor(unselectedColor); ? ? ? ? canvas.drawPath(centerPath, mPaint); ? ? ? ? canvas.drawPath(rightPath, mPaint); ? ? ? ? canvas.drawPath(bottomPath, mPaint); ? ? ? ? canvas.drawPath(leftPath, mPaint); ? ? ? ? canvas.drawPath(topPath, mPaint); ? ? ? ? if (!isSelected) return; ? ? ? ? mPaint.setColor(selectedColor); ? ? ? ? switch (mTouchArea) { ? ? ? ? ? ? case TouchArea.LEFT: ? ? ? ? ? ? ? ? canvas.drawPath(leftPath, mPaint); ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? case TouchArea.TOP: ? ? ? ? ? ? ? ? canvas.drawPath(topPath, mPaint); ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? case TouchArea.RIGHT: ? ? ? ? ? ? ? ? canvas.drawPath(rightPath, mPaint); ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? case TouchArea.BOTTOM: ? ? ? ? ? ? ? ? canvas.drawPath(bottomPath, mPaint); ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? case TouchArea.CENTER: ? ? ? ? ? ? ? ? canvas.drawPath(centerPath, mPaint); ? ? ? ? ? ? ? ? break; ? ? ? ? } ? ? ? ? Log.e("zhen", " touchArea: " + mTouchArea); ? ? ? ? //Android還提供了一個(gè)RegionIterator來(lái)對(duì)Region中的所有矩陣進(jìn)行迭代, ? ? ? ? // 可以使用該類,獲得某個(gè)Region的所有矩陣 ? ? ? ? //通過(guò)遍歷region中的矩陣,并繪制出來(lái),來(lái)繪制region // ? ? ? ?mPaint.setColor(Color.RED); // ? ? ? ?RegionIterator iterator = new RegionIterator(topRegion); // ? ? ? ?Rect r = new Rect(); // ? ? ? ?while (iterator.next(r)) { // ? ? ? ? ? ?canvas.drawRect(r, mPaint); // ? ? ? ?} // // ? ? ? ?mPaint.setColor(Color.BLUE); // ? ? ? ?RegionIterator iterator1 = new RegionIterator(leftRegion); // ? ? ? ?Rect r1 = new Rect(); // ? ? ? ?while (iterator1.next(r1)) { // ? ? ? ? ? ?canvas.drawRect(r1, mPaint); // ? ? ? ?} // // ? ? ? ?mPaint.setColor(Color.BLACK); // ? ? ? ?RegionIterator iterator2 = new RegionIterator(rightRegion); // ? ? ? ?Rect r2 = new Rect(); // ? ? ? ?while (iterator2.next(r2)) { // ? ? ? ? ? ?canvas.drawRect(r2, mPaint); // ? ? ? ?} // // ? ? ? ?mPaint.setColor(Color.YELLOW); // ? ? ? ?RegionIterator iterator3 = new RegionIterator(bottomRegion); // ? ? ? ?Rect r3 = new Rect(); // ? ? ? ?while (iterator3.next(r3)) { // ? ? ? ? ? ?canvas.drawRect(r3, mPaint); // ? ? ? ?} // // ? ? ? ?mPaint.setColor(Color.GREEN); // ? ? ? ?RegionIterator iterator4 = new RegionIterator(centerRegion); // ? ? ? ?Rect r4 = new Rect(); // ? ? ? ?while (iterator4.next(r4)) { // ? ? ? ? ? ?canvas.drawRect(r4, mPaint); // ? ? ? ?} ? ? } ? ? private MenuListener mListener; ? ? public void setListener(MenuListener listener) { ? ? ? ? mListener = listener; ? ? } ? ? // 點(diǎn)擊事件監(jiān)聽(tīng)器 ? ? public interface MenuListener { ? ? ? ? void onMenuClicked(int type, boolean isSelected); ? ? } }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android實(shí)現(xiàn)自動(dòng)變換大小的ViewPager
- android?viewpager實(shí)現(xiàn)輪播效果
- Android使用ViewPager實(shí)現(xiàn)翻頁(yè)效果
- Android單選多選按鈕的使用方法
- Android實(shí)現(xiàn)單選按鈕
- Android 中使用RadioGroup和Fragment實(shí)現(xiàn)底部導(dǎo)航欄的功能
- Android基礎(chǔ)控件RadioGroup使用方法詳解
- Android RadioGroup多行顯示效果 解決單選問(wèn)題
- Kotlin RadioGroup與ViewPager實(shí)現(xiàn)底層分頁(yè)按鈕方法
相關(guān)文章
Android實(shí)現(xiàn)跨進(jìn)程接口回掉的方法
這篇文章主要給大家介紹了關(guān)于Android如何實(shí)現(xiàn)跨進(jìn)程接口回掉的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)各位Android開(kāi)發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05Android實(shí)現(xiàn)桌面懸浮窗、蒙板效果實(shí)例代碼
這篇文章主要介紹了Android實(shí)現(xiàn)桌面懸浮窗、蒙板效果實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2016-05-05設(shè)備APP開(kāi)發(fā)環(huán)境配置細(xì)節(jié)介紹
隨著工業(yè)自動(dòng)化的不斷發(fā)展,設(shè)備APP也越來(lái)越重要,本文就設(shè)備APP開(kāi)發(fā)軟件配置細(xì)節(jié)做一個(gè)深入詳解2022-09-09Android Splash界面白屏、黑屏問(wèn)題的解決方法
這篇文章主要為大家詳細(xì)介紹了Android Splash界面白屏、黑屏問(wèn)題的解決方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09android實(shí)現(xiàn)注冊(cè)登錄程序
這篇文章主要為大家詳細(xì)介紹了android實(shí)現(xiàn)注冊(cè)登錄程序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04Android開(kāi)發(fā)之全屏與非全屏的切換設(shè)置方法小結(jié)
這篇文章主要介紹了Android開(kāi)發(fā)之全屏與非全屏的切換設(shè)置方法,結(jié)合實(shí)例形式分析了Android全屏切換靜態(tài)與動(dòng)態(tài)兩種實(shí)現(xiàn)方法,需要的朋友可以參考下2017-08-08