国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 系統(tǒng) > Android > 正文

Android自定義收音機(jī)搜臺(tái)控件RadioRulerView

2019-12-12 03:02:57
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

前言:像這類(lèi)的自定義控件有非常多的開(kāi)源項(xiàng)目,但還是沒(méi)有找到我項(xiàng)目想要的,所以簡(jiǎn)單實(shí)現(xiàn)了一個(gè),下面簡(jiǎn)單講講實(shí)現(xiàn)原理。

效果圖:

image

實(shí)現(xiàn)思路:

首先畫(huà)固定背景尺子,而實(shí)現(xiàn)這個(gè)則要計(jì)算刻度線(xiàn)的寬度、刻度線(xiàn)間的距離,以及要確定刻度線(xiàn)的總是,根據(jù)這些可以求出第一條刻度線(xiàn)的x坐標(biāo),使得整個(gè)尺子居中;下圖為尺子尺寸的計(jì)算方法:

image

貼上關(guān)鍵代碼:

 /** * 畫(huà)固定的尺子 * @param canvas */ private void drawLine(Canvas canvas) { canvas.save(); int height = mHeight; int drawCount = 0;//已經(jīng)畫(huà)了刻度線(xiàn)的個(gè)數(shù) float xPosition; for(int i=0; drawCount<=mMaxLineCount; i++){  xPosition = (mLineDivider*mDensity + mLineWidth)*drawCount + mLeftWidth;  if(i%5 == 0 && i%10 != 0){//刻度為5的倍數(shù),但同時(shí)不是10的倍數(shù)  canvas.drawLine(xPosition,height*0.85f-mPaddingBottom,xPosition,height*0.15f+mPaddingTop,mLinePaint);  }else if(i%10 == 0){//刻度為10的倍數(shù)  canvas.drawLine(xPosition,height-mPaddingBottom,xPosition,mPaddingTop,mLinePaint);  }else {//普通的刻度  canvas.drawLine(xPosition,height*0.75f-mPaddingBottom,xPosition,height*0.25f+mPaddingTop,mLinePaint);  }  drawCount++; } canvas.restore(); }

然后畫(huà)出可以拖動(dòng)的刻度線(xiàn)(首圖粉紅色線(xiàn)),要實(shí)現(xiàn)該功能其實(shí)不難,第一種情況:通過(guò)在onTouch里面獲取event.getX()坐標(biāo),而在這其中用到PointF類(lèi)來(lái)保存x坐標(biāo),然后根據(jù)x坐標(biāo)在onDraw()里面繪制即可;第二種情況:自動(dòng)搜臺(tái),這其實(shí)很簡(jiǎn)單,開(kāi)啟子線(xiàn)程每Thread.sleep(200)就累加一定x值即可實(shí)現(xiàn);

最后通過(guò)回調(diào)把計(jì)算好的值傳遞到Activity中,任務(wù)完成!

要是不太清楚回調(diào)原理的可看我另外一篇博客:Android回調(diào)與觀(guān)察者模式的實(shí)現(xiàn)原理

下面貼上View的源碼:

package com.xhunmon.radiorule;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.PointF;import android.util.AttributeSet;import android.util.SparseArray;import android.view.MotionEvent;import android.view.View;/** * user: uidq0530 ,date: 2017-04-16. * description:收音機(jī)FM搜臺(tái)尺子 * * @author xhunmon */public class RadioRulerView extends View { private static final String tag = "RadioRulerView"; private int mHeight; //view的高度 private int mWidth; //view的寬度 private Paint mLinePaint; //固定的尺子畫(huà)筆 private int mLineWidth;//尺子刻度線(xiàn)的寬 private int mLineColor;//固定尺子刻度線(xiàn)的顏色 private int mMoveLineColor;//移動(dòng)尺子刻度線(xiàn)的顏色 private float mDensity; private int mLineDivider; //兩條刻度線(xiàn)間的距離 private float mLeftWidth; //尺子離view左邊的距離 private int mMaxLineCount = 220; //總共要畫(huà)多少條刻度 private Paint mMoveLinePaint; //移動(dòng)尺子的畫(huà)筆 private int mValue; //尺子被選中的值 private float mMaxX; //onTouch中能觸摸的最大x值 private float mMinX; //onTouch中能觸摸的最小x值 private OnValueChangeListener mListener; private SparseArray<PointF> activePointers; private PointF xPoint; private int mPaddingBottom; private int mPaddingTop; private boolean mIsAuto = false; public RadioRulerView(Context context) { this(context,null); } public RadioRulerView(Context context, AttributeSet attrs) { this(context, attrs,0); } public RadioRulerView(Context context, AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr,0); } public RadioRulerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); mDensity = context.getResources().getDisplayMetrics().density; TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RadioRulerView, defStyleAttr, defStyleRes); mLineWidth = (int) a.getDimension(R.styleable.RadioRulerView_line_width,5*mDensity); mLineDivider = (int) a.getDimension(R.styleable.RadioRulerView_line_divider,15*mDensity); mLineColor = a.getColor(R.styleable.RadioRulerView_line_color,0xff888888); mMoveLineColor = a.getColor(R.styleable.RadioRulerView_move_line_color,0xffff0000); a.recycle(); init(); } private void init() { activePointers = new SparseArray<>(); mLinePaint = new Paint(); mLinePaint.setAntiAlias(true); mLinePaint.setColor(mLineColor); mLinePaint.setStrokeWidth(mLineWidth); mLinePaint.setStyle(Paint.Style.STROKE); mMoveLinePaint = new Paint(); mMoveLinePaint.setAntiAlias(true); mMoveLinePaint.setColor(mMoveLineColor); mMoveLinePaint.setStrokeWidth(mLineWidth); mMoveLinePaint.setStyle(Paint.Style.STROKE); } //此方法在view的尺寸確定后調(diào)用 @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mHeight = getHeight(); mWidth = getWidth(); mPaddingBottom = getPaddingBottom(); mPaddingTop = getPaddingTop(); mLeftWidth = (mWidth - mMaxLineCount*(mLineWidth +mLineDivider))/2; mMaxX = mMaxLineCount*(mLineWidth +mLineDivider) + mLeftWidth; mMinX = mLeftWidth; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); drawLine(canvas); drawMoveLine(canvas); } /** * 畫(huà)固定的尺子 * @param canvas */ private void drawLine(Canvas canvas) { canvas.save(); int height = mHeight; int drawCount = 0;//已經(jīng)畫(huà)了刻度線(xiàn)的個(gè)數(shù) float xPosition; for(int i=0; drawCount<=mMaxLineCount; i++){  xPosition = (mLineDivider*mDensity + mLineWidth)*drawCount + mLeftWidth;  if(i%5 == 0 && i%10 != 0){//刻度為5的倍數(shù),但同時(shí)不是10的倍數(shù)  canvas.drawLine(xPosition,height*0.85f-mPaddingBottom,xPosition,height*0.15f+mPaddingTop,mLinePaint);  }else if(i%10 == 0){//刻度為10的倍數(shù)  canvas.drawLine(xPosition,height-mPaddingBottom,xPosition,mPaddingTop,mLinePaint);  }else {//普通的刻度  canvas.drawLine(xPosition,height*0.75f-mPaddingBottom,xPosition,height*0.25f+mPaddingTop,mLinePaint);  }  drawCount++; } canvas.restore(); } /** * 搜索FM頻道的刻度線(xiàn) * @param canvas */ private void drawMoveLine(Canvas canvas) { canvas.save(); xPoint = activePointers.valueAt(0); if (xPoint != null) {  canvas.drawLine(xPoint.x,mHeight-mPaddingBottom, xPoint.x,mPaddingTop,mMoveLinePaint);  setValue(eventXValue(xPoint.x)); }else {  canvas.drawLine(mMinX,mHeight-mPaddingBottom, mMinX,mPaddingTop,mMoveLinePaint); } canvas.restore(); } @Override public boolean onTouchEvent(MotionEvent event) { int pointerIndex = event.getActionIndex(); int pointerId = event.getPointerId(pointerIndex); switch (event.getActionMasked()) {  case MotionEvent.ACTION_DOWN:  case MotionEvent.ACTION_POINTER_DOWN: {  float downX = event.getX(pointerIndex);  if(downX > mMaxX || downX < mMinX) break;  PointF position = new PointF(downX, event.getY(pointerIndex));  activePointers.put(pointerId, position);  break;  }  case MotionEvent.ACTION_MOVE: {  int pointerCount = event.getPointerCount();  for (int i = 0; i < pointerCount; i++) {   PointF point = activePointers.get(event.getPointerId(i));   if (point == null) continue;   float moveX = event.getX(i);   if(moveX > mMaxX || moveX < mMinX) break;   point.x = event.getX(i);   point.y = event.getY(i);  }  break;  }  case MotionEvent.ACTION_UP:  case MotionEvent.ACTION_POINTER_UP:  case MotionEvent.ACTION_CANCEL: {  int pointerCount = event.getPointerCount();  PointF point = activePointers.get(event.getPointerId(pointerCount-1));  if (point == null) break;  float upX = event.getX(pointerCount-1);  if(upX > mMaxX || upX < mMinX) break;  point.x = eventXValue(event.getX(pointerCount-1));  point.y = event.getY(pointerCount-1);  break;  } } invalidate(); return true; } /** *作用:使得放手后MoveLine和Line重合;精確mValue * @param x onTouch中的event.getX() * @return */ public int eventXValue(float x){ mLineDivider = (int) (mLineDivider*mDensity); return (int) ((x-mLeftWidth)%(mLineWidth +mLineDivider)>((mLineWidth +mLineDivider)/2)   ? (((mLineWidth +mLineDivider)*((int)((x-mLeftWidth)/(mLineWidth +mLineDivider))+1))+mLeftWidth)   : (((mLineWidth +mLineDivider)*((int)((x-mLeftWidth)/(mLineWidth +mLineDivider))))+mLeftWidth)); } /** * 設(shè)置最大刻度線(xiàn)個(gè)數(shù) * @param count */ public void setMaxLineCount(int count) { mMaxLineCount = count; } /** * 設(shè)置是否啟用自動(dòng)搜索功能 * @param isAuto */ public void setAutoSearchFM(boolean isAuto){ this.mIsAuto = isAuto; } /** * 開(kāi)始自動(dòng)搜臺(tái) */ public void startAutoSeachFM(){ if(mIsAuto)  new Thread(new SeachThread()).start(); } /** * 搜臺(tái)要在開(kāi)啟子線(xiàn)程 */ private class SeachThread implements Runnable{ @Override public void run() {  while(mIsAuto){  xPoint = activePointers.valueAt(0);  if(xPoint != null){   xPoint.x += (mLineWidth + mLineDivider);   if(xPoint.x > mMaxX) xPoint.x = mLeftWidth;  }else {   PointF position = new PointF(mLeftWidth, mHeight);   activePointers.put(0, position);  }  try {   Thread.sleep(200);  } catch (InterruptedException e) {   e.printStackTrace();  }  postInvalidate();  } } } /*****************************值傳遞的回調(diào)*************************************/ public interface OnValueChangeListener { void onValueChange(float value); } public void setOnValueChangeListener(OnValueChangeListener listener){ mListener = listener; } private void setValue(float value) { if(mListener != null){  mValue = (int) ((value - mLeftWidth)/(mLineDivider*mDensity + mLineWidth));  //FM的范圍從88.0 ~ 108.0  mListener.onValueChange(mValue/10f + 88); } } /******************************************************************/}

貼上Activity代碼:

package com.xhunmon.radiorule;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.CheckBox;import android.widget.CompoundButton;import android.widget.TextView;public class MainActivity extends Activity implements RadioRulerView.OnValueChangeListener, CompoundButton.OnCheckedChangeListener, View.OnClickListener { private TextView mShow; private RadioRulerView mRule; private CheckBox mCbAuto; private Button mBtStart; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mShow = (TextView) findViewById(R.id.tv); mRule = (RadioRulerView) findViewById(R.id.rule); mCbAuto = (CheckBox) findViewById(R.id.cb_auto); mBtStart = (Button) findViewById(R.id.bt_start); mRule.setMaxLineCount(200);//FM從88.0 ~ 108.0總共有200頻道 mRule.setOnValueChangeListener(this); mCbAuto.setOnCheckedChangeListener(this); mBtStart.setOnClickListener(this); } @Override public void onValueChange(float value) { mShow.setText("FM:"+value); } @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if(isChecked){  mRule.setAutoSearchFM(true); }else {  mRule.setAutoSearchFM(false); } } @Override public void onClick(View v) { if(v.getId() == R.id.bt_start){  mRule.startAutoSeachFM(); } }}

整個(gè)項(xiàng)目都放在github上面了,歡迎做客與討論:
https://github.com/xhunmon/RadioRule

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持武林網(wǎng)。

發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 和平区| 邓州市| 汕头市| 南涧| 黄浦区| 乌兰浩特市| 依安县| 太湖县| 大竹县| 旌德县| 胶南市| 蓝山县| 桐柏县| 玉环县| 华容县| 若羌县| 威宁| 璧山县| 盐亭县| 枣阳市| 公主岭市| 吉木萨尔县| 凭祥市| 禹州市| 平安县| 安徽省| 江安县| 高陵县| 大埔区| 漾濞| 镇远县| 云南省| 宝兴县| 沂南县| 登封市| 天津市| 蓬莱市| 洞口县| 昌江| 弋阳县| 安陆市|