日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

自定义View-实现简易车速器(真的够简易)

發(fā)布時間:2025/3/15 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 自定义View-实现简易车速器(真的够简易) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

自定義View-實現(xiàn)簡易車速器(真的夠簡易)

  學習自定義View挺久了,好久沒用都快忘了,這里實現(xiàn)一個簡易的車速器算是一個回顧,項目比較簡單,代碼較少,但自定義View的流程基本都涉及到了.本文不是一篇講解自定義View基礎的文章,而是一個小的實戰(zhàn),如果想看講解自定義View的文章,強烈推薦博客:http://blog.csdn.net/aigestudio,強烈=_=.
效果如下圖:

接下來是代碼部分:

attrs:

<?xml version="1.0" encoding="utf-8"?> <resources><declare-styleable name="SpeedometerView"><attr name="centerCircleWidth" format="dimension"/><attr name="outCircleWidth" format="dimension"/><attr name="whiteScaleWidth" format="dimension"/><attr name="redScaleWidth" format="dimension"/><attr name="numberWidth" format="dimension"/><attr name="pointerWidth" format="dimension"/><attr name="outCircleColor" format="color"/><attr name="innerCircleColor" format="color"/><attr name="numberColor" format="color"/><attr name="normalScaleColor" format="color"/><attr name="multipleOfTenScaleColor" format="color"/></declare-styleable> </resources>

attrs文件包含自定義的屬性,可以在布局文件或者代碼中使用.

colors:

<?xml version="1.0" encoding="utf-8"?> <resources><color name="colorPrimary">#3F51B5</color><color name="colorPrimaryDark">#303F9F</color><color name="colorAccent">#FF4081</color><color name="color_out_arc">@android:color/holo_red_dark</color><color name="color_full_ten_number">@android:color/holo_red_dark</color><color name="color_inner_arc">@android:color/white</color><color name="color_full_ten_indicator">@android:color/holo_red_dark</color><color name="color_not_full_ten_indicator">@android:color/white</color> </resources>

布局文件:

<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"xmlns:SpeedometerView="http://schemas.android.com/apk/res-auto"android:id="@+id/activity_main"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@android:color/darker_gray"tools:context="com.example.why.speedometerview.MainActivity"><com.example.why.speedometerview.SpeedometerViewandroid:background="@android:color/black"android:id="@+id/speedometer_view"android:layout_width="match_parent"android:layout_height="match_parent"SpeedometerView:outCircleWidth="5dp"/> </FrameLayout>

接下來是Java代碼:
  
  SpeedometerView:

/*** Created by why on 17-3-9.* @author why* 簡易View實現(xiàn)類*/public class SpeedometerView extends View {private static final String TAG = "SpeedometerView";private Paint mInnerArcPaint; // 內部弧線畫筆private Paint mOutArcPaint; // 外部弧線畫筆private Paint mNotFullTenIndicatorPaint; // 非整10刻度畫筆private Paint mFullTenIndicatorPaint; // 整10加粗刻度畫筆private Paint mNumberPaint; // 數(shù)字畫筆private Paint mIndicatorPathPaint; // 刻度指針畫筆,計可旋轉的線條private int mInnerArcLineWidth; // 內部弧線線條寬度private int mOutArcLineWidth; // 外部弧線線條寬度private int mNormalIndicatorWidth; // 刻度線條寬度private int mFullTenScaleWidth; // 整10加粗刻度線條寬度private int mFullTenScaleLen ; // 非整10加粗線條長度private int mNotFullScaleLen; // 白色刻度線條長度private int mNumberWidth; // 數(shù)字線條刻度private int mIndicatorPathLineWidth;//private float mNumberTextSize; // 數(shù)字字體大小private int mCenterCircleRadius; // 內圓半徑private int mOutCircleRadius; // 外圓半徑private RectF mOutRectF; // 外弧線的基準矩形private RectF mCenterRectF; //內弧線基準矩形// 這兩個值是當view的width和height屬性為wrap_content時,屬性不起作用配置的默認值,詳情間onMeasure();private int mViewDefaultWidth; // 默認的view的寬度private int mViewDefaultHeight; // 默認的view的高度,private int[] mWindowSize = new int[2]; // 保存屏幕的寬/高private Path mIndicatorPath; // 刻度指針,用path實現(xiàn)private int mScaleIndicatorLen; // 刻度指針的長度private int mIndicatorX; // 刻度指針指尖的X坐標private int mIndicatorY; // 刻度指針指尖的Y坐標private int mOutArcColor = Color.RED; // 外部弧線默認顏色private int mNumberColor =Color.RED; // 刻度數(shù)字默認顏色private int mInnerArcColor = Color.WHITE; //內部弧線默認顏色private int mFullTenIndicatorColor = Color.RED; // 整10刻度顏色private int mNotFullTenIndicatorColor = Color.WHITE; // 非整10刻度顏色public SpeedometerView(Context context) {super(context);init(context,null,0);}public SpeedometerView(Context context, AttributeSet attrs) {super(context,attrs);init(context,attrs,0);}public SpeedometerView(Context context, AttributeSet attrs, int defStyleAttr) {super(context,attrs,defStyleAttr);init(context,attrs,defStyleAttr);}/*** 初始化默認數(shù)值*/private void initSize(){mWindowSize = getWindowSize();mViewDefaultWidth = mWindowSize[0];mViewDefaultHeight = mWindowSize[1];mOutCircleRadius = mWindowSize[0]/2-20;mNumberTextSize = mOutCircleRadius / 13;mInnerArcLineWidth = mOutCircleRadius/150;mCenterCircleRadius = mOutCircleRadius / 8;mOutArcLineWidth = mOutCircleRadius /150;mNormalIndicatorWidth = mOutCircleRadius /150;mFullTenScaleWidth = mOutCircleRadius / 150;mFullTenScaleLen = mOutCircleRadius /6;mNotFullScaleLen = mOutCircleRadius / 7;mIndicatorPathLineWidth = mOutCircleRadius/100;mNumberWidth = mOutCircleRadius/100;}/*** 初始化默認顏色*/private void initColor() {Context context = getContext();mOutArcColor = ContextCompat.getColor(context, R.color.color_out_arc);mNumberColor = ContextCompat.getColor(context, R.color.color_full_ten_number);mInnerArcColor = ContextCompat.getColor(context, R.color.color_inner_arc);mFullTenIndicatorColor = ContextCompat.getColor(context, R.color.color_full_ten_indicator);mNotFullTenIndicatorColor = ContextCompat.getColor(context,R.color.color_not_full_ten_indicator);}/*** 初始化* @param context* @param attrs* @param defStyleAttr*/private void init(Context context,AttributeSet attrs, int defStyleAttr){initSize(); //為各個屬性設置默認的值initColor(); //設置默認顏色//從xml獲取設置的屬性,注意:這里只提供顏色屬性if (attrs != null) {TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.SpeedometerView,defStyleAttr,0);mOutArcColor = typedArray.getColor(R.styleable.SpeedometerView_outCircleColor,mOutArcColor);mNumberColor = typedArray.getColor(R.styleable.SpeedometerView_numberColor, mNumberColor);mInnerArcColor = typedArray.getColor(R.styleable.SpeedometerView_innerCircleColor, mInnerArcColor);mNotFullTenIndicatorColor = typedArray.getColor(R.styleable.SpeedometerView_normalScaleColor, mNotFullTenIndicatorColor);mFullTenIndicatorColor = typedArray.getColor(R.styleable.SpeedometerView_multipleOfTenScaleColor, mFullTenIndicatorColor);typedArray.recycle();}//設置內弧線畫筆mInnerArcPaint = new Paint();mInnerArcPaint.setStyle(Paint.Style.STROKE);mInnerArcPaint.setColor(mInnerArcColor);mInnerArcPaint.setAntiAlias(true); //抗鋸齒mInnerArcPaint.setStrokeWidth(mInnerArcLineWidth);//設置外弧線畫筆mOutArcPaint = new Paint();mOutArcPaint.setStyle(Paint.Style.STROKE);mOutArcPaint.setColor(mOutArcColor);mOutArcPaint.setAntiAlias(true);mOutArcPaint.setStrokeWidth(mOutArcLineWidth);//設置非整十刻度畫筆mNotFullTenIndicatorPaint = new Paint();mNotFullTenIndicatorPaint.setStyle(Paint.Style.FILL);mNotFullTenIndicatorPaint.setColor(mNotFullTenIndicatorColor);mNotFullTenIndicatorPaint.setAntiAlias(true);mNotFullTenIndicatorPaint.setStrokeWidth(mNormalIndicatorWidth);//設置整十刻度畫筆mFullTenIndicatorPaint = new Paint();mFullTenIndicatorPaint.setStyle(Paint.Style.FILL);mFullTenIndicatorPaint.setColor(mFullTenIndicatorColor);mFullTenIndicatorPaint.setAntiAlias(true);mFullTenIndicatorPaint.setStrokeWidth(mFullTenScaleWidth);//設置數(shù)字畫筆mNumberPaint = new Paint();mNumberPaint.setStyle(Paint.Style.FILL);mNumberPaint.setColor(mNumberColor);mNumberPaint.setAntiAlias(true);mNumberPaint.setStrokeWidth(mNumberWidth);mNumberPaint.setTextSize(mNumberTextSize);mNumberPaint.setTextAlign(Paint.Align.CENTER);//設置刻度指針畫筆mIndicatorPathPaint = new Paint();mIndicatorPathPaint.setAntiAlias(true);mIndicatorPathPaint.setStyle(Paint.Style.STROKE);mIndicatorPathPaint.setColor(Color.RED);mIndicatorPathPaint.setStrokeWidth(mIndicatorPathLineWidth);mScaleIndicatorLen = mOutCircleRadius*8/13;//指針的長度mIndicatorX = -mScaleIndicatorLen;//因為指針一開始是放在-180°的位置mIndicatorY = 0; //指針的起止坐標為內圓的圓心(onDraw()中會把原點坐標平移到屏幕的中心,方便畫圖),所以y為0mIndicatorPath = new Path();mOutRectF = new RectF();mCenterRectF = new RectF();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);//通過MeasureSpec獲取各自的mode和sizeint widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);/*** 這里這么做的原因是自定義View的時,width或者height的屬性wrap_content不起作用,效果和match_parant相同,這里有牽扯到自* View扥繪制流程這里暫時不表,建議看看《Android開發(fā)藝術探索》中自定義View篇章或者看官網(wǎng)和相應的博客,這里只是當屬性為* wrap_content時設置默認的mViewDefaultWidth,mViewDefaultHeight;*/if (widthSpecMode == MeasureSpec.AT_MOST && heightMeasureSpec == MeasureSpec.AT_MOST) {setMeasuredDimension(mViewDefaultWidth, mViewDefaultHeight);}else if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode != MeasureSpec.AT_MOST) {setMeasuredDimension(mViewDefaultWidth, heightSpecSize);}else if (widthMeasureSpec != MeasureSpec.AT_MOST && heightMeasureSpec == MeasureSpec.AT_MOST){setMeasuredDimension(widthSpecSize, heightMeasureSpec);}else {setMeasuredDimension(widthSpecSize, heightSpecSize);}}/*** 在onDraw(Canvas canvas)中畫圖,每次調用重繪方法invalidate()都會再次調用onDraw(Canvas canvas);* @param canvas*/@Overrideprotected void onDraw(Canvas canvas) {canvas.translate(mWindowSize[0]/2, mWindowSize[1]/2);//canvas坐標平移到屏幕中心,這樣容易操作//畫外層的弧形,默認紅色drawOutArc(mOutRectF, canvas);//畫內層的弧形,默認白色drawInnerWhiteArc(mCenterRectF, canvas);//畫整十刻度以及整10數(shù)字drawFullTenIndicatorAndNumber(canvas);//接下來畫普通的刻度,即未加粗的刻度drawNotFullTenIndicator(canvas);//接下來畫指示圖標,注意這里使用path的drawPath()方法畫line,每次畫之前path調用path.lineTo(mIndicatorX, mIndicatorY)//連接內圓心和該點drawIndicator(mIndicatorPath, canvas);}/*** 獲取觸摸的坐標* @param event* @return*/@Overridepublic boolean onTouchEvent(MotionEvent event) {int action = MotionEventCompat.getActionMasked(event);float posX;float posY;double scale;switch (action) {case MotionEvent.ACTION_DOWN:posX = event.getX();posY = event.getY();//如果觸摸的坐標不在弧線的基準矩形中,那就不做處理,直接returnif (!mOutRectF.contains(posX-mWindowSize[0]/2,posY - mWindowSize[1]/2) || posY - mWindowSize[1]/2 > 0){return true;}/*** 由于刻度指針的長度是固定的,但是手指觸摸的點不是固定的,不能直接將指針的終點坐標設置為獲取的x,y,但可以先算出*手指觸摸的點到內圓中心的距離,然后除于指針的長度,得到比例,根據(jù)相似三角形的性質可知,這個比例對于三角形的三條邊都是一樣的*注意:這里的三角形是假設圓心,觸摸點,以及X坐標相連獲得的直角三角形,于是我們可以根據(jù)比例算出在點與內圓心的距離為默認的指針*長度時,此時另外兩條直角邊的長度,即可求出,x,y的值*/scale = Math.sqrt((posX-mWindowSize[0]/2)*(posX-mWindowSize[0]/2)+ (posY - mWindowSize[1]/2)*(posY - mWindowSize[1]/2))/mScaleIndicatorLen;mIndicatorX = rawXToIndicatorX(posX, scale);mIndicatorY = rawXToIndicatorY(posY, scale);break;case MotionEvent.ACTION_MOVE://移動過程中不斷的獲取觸摸點的坐標,并按比例轉換為相應的指針終點坐標posX = event.getX();posY = event.getY();if (!mOutRectF.contains(posX-mWindowSize[0]/2,posY - mWindowSize[1]/2)|| posY - mWindowSize[1]/2 > 0){return true;}Log.d(TAG,"x的="+posX+"--y的值=" +""+posY);scale = Math.sqrt((posX-mWindowSize[0]/2)*(posX-mWindowSize[0]/2)+ (posY - mWindowSize[1]/2)*(posY - mWindowSize[1]/2))/mScaleIndicatorLen;//或最終的指針終點坐標,onDraw()根據(jù)mIndicatorX.mIndicatorY畫指針的終點mIndicatorX = rawXToIndicatorX(posX, scale);mIndicatorY = rawXToIndicatorY(posY, scale);break;}//重新繪制view,onDraw()會被調用invalidate();//return true表示自己處理觸摸事件,parent的onTouchEvent()方法不會被調用了return true;}/*** 按邊長比例算出最終的X* @param posX* @param scale* @return*/private int rawXToIndicatorX(double posX, double scale) {return (int)((posX-mWindowSize[0]/2) / scale);}/*** 按邊長比例算出最終的Y* @param posY* @param scale* @return*/private int rawXToIndicatorY(double posY, double scale) {return (int)((posY - mWindowSize[1]/2) / scale);}/*** 畫出外弧線* @param rectF* @param canvas*/private void drawOutArc(RectF rectF, Canvas canvas) {rectF.set(-mOutCircleRadius, - mOutCircleRadius, mOutCircleRadius, mOutCircleRadius);canvas.drawArc(mOutRectF,0,-180,false,mOutArcPaint);}//畫出內弧線private void drawInnerWhiteArc(RectF rectF, Canvas canvas) {rectF.set(-mCenterCircleRadius, -mCenterCircleRadius,mCenterCircleRadius, mCenterCircleRadius);canvas.drawArc(mCenterRectF, 0, -180, false, mInnerArcPaint);}/*** 畫整10的刻度,因為數(shù)字對應整時,可在同一個循環(huán)中畫出* @param canvas*/private void drawFullTenIndicatorAndNumber(Canvas canvas) {//整十刻度終點離內圓心的長度int distance = mOutCircleRadius - mFullTenScaleLen;//接下來畫10的倍數(shù)的刻度for (int i = -180; i<=0; i += 15) {double radian = ((double)i/180)*Math.PI;//弧度double cosValue = Math.cos(radian);//三角函數(shù)值double sinValue = Math.sin(radian);//根據(jù)弧度算出起始點和終點坐標float startX = (float)(distance*cosValue);float startY = (float)(distance*sinValue);float endX = (float)(mOutCircleRadius*Math.cos(radian));float endY = (float)(mOutCircleRadius*Math.sin(radian));canvas.drawLine(startX,startY,endX,endY,mFullTenIndicatorPaint);//刻度數(shù)字標識的坐標,float numberX =(float)((distance-50)*cosValue);float numberY =(float)((distance-50)*sinValue);canvas.drawText(""+Math.abs(i+180)*2/3,numberX, numberY, mNumberPaint);}}/*** 畫非整10刻度* @param canvas*/private void drawNotFullTenIndicator(Canvas canvas) {float normalIntervalRadian = (float)Math.PI / 60;int normalIntervalRadianCount = (int)(Math.PI/normalIntervalRadian);int distance = mOutCircleRadius - mNotFullScaleLen;for (int i = 0; i <= normalIntervalRadianCount; i++) {if (!(i%5 == 0) ){float cosValue = (float)Math.cos(-normalIntervalRadian*i);float sinValue = (float)Math.sin(-normalIntervalRadian*i);float startX = (distance*cosValue);float startY = (distance*sinValue);float endX = (float)((mOutCircleRadius-10)*Math.cos((-normalIntervalRadian*i)));float endY = (float)((mOutCircleRadius-10)*Math.sin((-normalIntervalRadian*i)));canvas.drawLine(startX,startY,endX,endY,mNotFullTenIndicatorPaint);}}}/*** 畫刻度指針* @param path* @param canvas*/private void drawIndicator(Path path, Canvas canvas) {path.lineTo(mIndicatorX, mIndicatorY);canvas.drawPath(path,mIndicatorPathPaint);path.reset();}/*** 獲取屏幕的寬,高,按屏幕的比例設置view的各個屬性* @return*/private int[] getWindowSize() {int[] size = new int[2];Resources resources = getContext().getResources();DisplayMetrics displayMetrics = resources.getDisplayMetrics();size[0] = displayMetrics.widthPixels;size[1] = displayMetrics.heightPixels;return size;}//這里只提供修改顏色的方法public int getOutCircleColor() {return mOutArcColor;}public void setOutCircleColor(int outCircleColor) {this.mOutArcColor = outCircleColor;}public int getNumberColor() {return mNumberColor;}public void setmNumberColor(int numberColor) {this.mNumberColor = numberColor;}public int getInnerCircleColor() {return mInnerArcColor;}public void setInnerCircleColor(int innerArcColor) {this.mInnerArcColor = innerArcColor;}public int getmOutArcColor() {return mOutArcColor;}public void setmOutArcColor(int outArcColor) {this.mOutArcColor = outArcColor;}public int getmNumberColor() {return mNumberColor;}public int getmInnerArcColor() {return mInnerArcColor;}public void setmInnerArcColor(int innerArcColor) {this.mInnerArcColor = innerArcColor;}public int getmFullTenIndicatorColor() {return mFullTenIndicatorColor;}public void setmFullTenIndicatorColor(int fullTenIndicatorColor) {this.mFullTenIndicatorColor = fullTenIndicatorColor;}public int getmNotFullTenIndicatorColor() {return mNotFullTenIndicatorColor;}public void setmNotFullTenIndicatorColor(int notFullTenIndicatorColor) {this.mNotFullTenIndicatorColor = notFullTenIndicatorColor;} }

Activity:

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);SpeedometerView speedometerView = (SpeedometerView)findViewById(R.id.speedometer_view);} }

注釋還是很清楚的,源碼地址https://github.com/whyrookie/...

總結

以上是生活随笔為你收集整理的自定义View-实现简易车速器(真的够简易)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 日日天天 | www九九九 | 高潮爽爆喷水h | 极品美妇后花庭翘臀娇吟小说 | 日本不卡不卡 | 91亚洲精选 | 超碰在线网站 | 精品国产伦一区 | 亚洲老老头同性老头交j | 中文字幕一区二区人妻在线不卡 | 欧美日韩一区二区电影 | 青青草成人av | 国产三级久久久久 | 国产一区二区三区在线播放无 | 午夜三级在线观看 | 免费三级大片 | 国产极品一区 | 边添小泬边狠狠躁视频 | 欧美又粗又深又猛又爽啪啪九色 | 欧美三级久久久 | avtt国产| 欧美bdsm调教视频 | 日本精品视频在线播放 | 东京热一本视频一区 | 欧美99| 成人人人人人欧美片做爰 | 天天干一干 | 国产乱码精品一区二区三区中文 | 亚洲一区二区不卡视频 | 免费观看成人鲁鲁鲁鲁鲁视频 | 91视频在线观看视频 | 污视频网站免费 | 女人裸体无遮挡 | 少妇人妻偷人精品无码视频 | 国产精品视频一区二区三区 | 噜噜色综合 | 在线爱情大片免费观看大全 | 91香蕉一区二区三区在线观看 | 久久精品国产电影 | 在线看亚洲 | 51成人精品网站 | 综合久久综合久久 | 97青青草 | 国产美女av| 另类男人与善交video | 欧美日韩色综合 | 亚洲av无码久久精品色欲 | 国产黄在线播放 | 韩国成人在线视频 | 国产一区二区三区视频网站 | 亚洲高清久久久 | 久久福利精品 | 九色国产在线 | 青青草亚洲 | 日韩精品电影在线 | 天天干天天要 | 久久久999视频 | 黄网在线观看视频 | 天堂资源网 | 国产视频97 | 免费精品 | 久久久国产精华液999999 | 亚洲伦理一区二区 | 91免费黄色 | 日韩在线一区二区三区 | 99热99热 | 免费成人毛片 | 日本三级一区二区三区 | 97日韩精品 | 日韩精品无码一区二区三区久久久 | 天天干天天舔 | 伊人888| 日韩婷婷 | 热久久国产精品 | 日日干视频 | 亚洲国产精品成人久久蜜臀 | 日韩精品一区二区三区久久 | 永久免费在线播放 | 91超碰人人| 亚洲黄色精品 | 制服.丝袜.亚洲.中文.综合 | 亚洲国产成人一区二区精品区 | 日韩成人一区二区 | 超鹏在线视频 | 清冷学长被爆c躁到高潮失禁 | 在线一二区 | 国内精品嫩模av私拍在线观看 | 国产一级片毛片 | 精品少妇无码av无码专区 | 久久成人小视频 | 亚洲激情一区 | 亚洲免费三区 | 德国性经典xxxx性hd | 成人久草 | 男人天堂伊人 | 自拍偷拍亚洲一区 | 五月激情开心网 | 国产一区二区三区观看 | 日韩少妇高潮抽搐 |