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ì)算的)
- 畫(huà)布平移,繪制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)行迭代,
? ? ? ? // 可以使用該類(lèi),獲得某個(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)Unity3D下RTMP推送的示例
像Unity3D下的RTMP或RTSP播放器一樣,好多開(kāi)發(fā)者苦于在Unity環(huán)境下,如何高效率低延遲的把數(shù)據(jù)采集并編碼實(shí)時(shí)推送到流媒體服務(wù)器,實(shí)現(xiàn)Unity場(chǎng)景下的低延遲推拉流方案。本文介紹幾種RTMP推送的方案2021-06-06
android檢測(cè)SD卡讀寫(xiě)權(quán)限方法
今天小編就為大家分享一篇android檢測(cè)SD卡讀寫(xiě)權(quán)限方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-08-08
Android?Compose狀態(tài)改變動(dòng)畫(huà)animateXxxAsState使用詳解
這篇文章主要為大家介紹了Android?Compose狀態(tài)改變動(dòng)畫(huà)animateXxxAsState使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
Android fragment 轉(zhuǎn)場(chǎng)動(dòng)畫(huà)創(chuàng)建步驟
在 Android 中,可以使用 setCustomAnimations() 方法來(lái)繪制自定義的 Fragment 轉(zhuǎn)場(chǎng)動(dòng)畫(huà),本文分步驟給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-03-03
解決在eclipse中將android項(xiàng)目生成apk并且給apk簽名的實(shí)現(xiàn)方法詳解
本篇文章是對(duì)在eclipse中將android項(xiàng)目生成apk并且給apk簽名的實(shí)現(xiàn)方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
Android手機(jī)開(kāi)發(fā)設(shè)計(jì)之記事本功能
這篇文章主要為大家詳細(xì)介紹了Android手機(jī)開(kāi)發(fā)設(shè)計(jì)之記事本功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05
Android usb設(shè)備權(quán)限查詢及自動(dòng)獲取詳解流程
本篇文章介紹了我想要獲取Android系統(tǒng)usb設(shè)備使用權(quán)限時(shí)遇到的問(wèn)題,以及解決該問(wèn)題的過(guò)程及思路,通讀本篇對(duì)大家的學(xué)習(xí)或工作具有一定的價(jià)值,需要的朋友可以參考下2021-10-10
android獲取手機(jī)唯一標(biāo)識(shí)的方法
這篇文章主要介紹了獲取安卓的手機(jī)或者平板的唯一標(biāo)識(shí)的方法,需要的朋友可以參考下2014-02-02

