Android 自定義星評(píng)空間示例代碼
沒(méi)事做用自定義view方式寫(xiě)一個(gè)星評(píng)控件,雖說(shuō)網(wǎng)上很多這個(gè)控件,但是這是自己寫(xiě)的,在這里記錄一下。
首先需要自定義屬性
<declare-styleable name="Rate"> <!--屬性分別是:?jiǎn)蝹€(gè)的寬,高,之間的距離,激活的數(shù)量,總數(shù)量,激活的drawable,沒(méi)有激活的drawable,是否可以選擇數(shù)量--> <attr name="custom_rate_width" format="dimension"/> <attr name="custom_rate_height" format="dimension"/> <attr name="custom_rate_padding" format="dimension"/> <attr name="custom_rate_active_size" format="integer"/> <attr name="custom_rate_size" format="integer"/> <attr name="custom_rate_active_drawable" format="reference"/> <attr name="custom_rate_disactive_drawable" format="reference"/> <attr name="custom_rate_touch" format="boolean"/> </declare-styleable>
初始化代碼
protected void init(Context context, AttributeSet attrs) { TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.Rate); int activeId = 0; int disactiveId = 0; if (array != null) { size = array.getInt(R.styleable.Rate_custom_rate_size, 5); activeSize = array.getInt(R.styleable.Rate_custom_rate_active_size, 3); rateWidth = array.getDimensionPixelOffset(R.styleable.Rate_custom_rate_width, 0); rateHeight = array.getDimensionPixelOffset(R.styleable.Rate_custom_rate_height, 0); activeId = array.getResourceId(R.styleable.Rate_custom_rate_active_drawable, 0); disactiveId = array.getResourceId(R.styleable.Rate_custom_rate_disactive_drawable, 0); padding = array.getDimensionPixelOffset(R.styleable.Rate_custom_rate_padding, 0); isTouch = array.getBoolean(R.styleable.Rate_custom_rate_touch, false); array.recycle(); } //如果沒(méi)有寬高就設(shè)置一個(gè)默認(rèn)值 if (rateHeight <= 0){ rateHeight = 80; } if (rateWidth <= 0){ rateWidth = 80; } if (activeId!=0){ activeBitmap = BitmapFactory.decodeResource(getResources(), activeId); //如果沒(méi)有設(shè)置寬高時(shí)候 if (rateWidth <= 0) { rateWidth = activeBitmap.getWidth(); } //把圖片壓縮到設(shè)置的寬高 activeBitmap = Bitmap.createScaledBitmap(activeBitmap, (int) rateWidth, (int) rateHeight, false); } if (disactiveId != 0){ disactiveBitmap = BitmapFactory.decodeResource(getResources(), disactiveId); if (rateHeight <= 0) { rateHeight = activeBitmap.getHeight(); } disactiveBitmap = Bitmap.createScaledBitmap(disactiveBitmap, (int) rateWidth, (int) rateHeight, false); } mPaint = new Paint();//初始化bitmap的畫(huà)筆 mPaint.setAntiAlias(true); activPaint = new Paint();//初始化選中星星的畫(huà)筆 activPaint.setAntiAlias(true); activPaint.setColor(Color.YELLOW); disactivPaint = new Paint();//初始化未選中星星的畫(huà)筆 disactivPaint.setAntiAlias(true); disactivPaint.setColor(Color.GRAY); }
onMeasure方法設(shè)置View的寬高,如果設(shè)置的每一個(gè)星星控件的寬高大于實(shí)際view的寬高,就用星星空間的寬高作于view的寬高
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); //計(jì)算寬 if (widthMode == MeasureSpec.EXACTLY) { //如果view的寬度小于設(shè)置size*星星的寬度,就用size * (int) (padding + rateWidth)做為控件的寬度度 if (widthSize < size * (int) (padding + rateWidth)) { width = size * (int) (padding + rateWidth); } else { width = widthSize; } } else { width = size * (int) (padding + rateWidth)-padding; } //計(jì)算高 if (heightMode == MeasureSpec.EXACTLY) { //如果view的高度小于設(shè)置星星的高度,就用星星高度做為控件的高度 if (heightSize < rateHeight) { height = (int) rateHeight + 5; } else { height = heightSize; } } else { height = (int) rateHeight + 5; } setMeasuredDimension(width, height); }
onDraw方法中繪制
//開(kāi)始畫(huà)active for (int i = 0; i < activeSize; i++) { if (activeBitmap != null){ if (i == 0) { canvas.drawBitmap(activeBitmap, rateWidth * i, (height - rateHeight) / 2, mPaint); } else { canvas.drawBitmap(activeBitmap, (rateWidth + padding) * i, (height - rateHeight) / 2, mPaint); } }else { drawActivRate(i,canvas); } } // //開(kāi)始畫(huà)disactive for (int i = activeSize; i < size; i++) { if (disactiveBitmap != null){ if (i == 0) { canvas.drawBitmap(disactiveBitmap, rateWidth * i, (height - rateHeight) / 2, mPaint); } else { canvas.drawBitmap(disactiveBitmap, (rateWidth + padding) * i, (height - rateHeight) / 2, mPaint); } }else { drawDisActivRate(i,canvas); } }
上面用到兩個(gè)方法drawActivRate和drawDisActivRate,分別是在沒(méi)有設(shè)置活動(dòng)中的星星和不在活動(dòng)中星星的圖片的時(shí)候,繪制在活動(dòng)和不在活動(dòng)的默認(rèn)星星:
/** * 繪制黃色的五角星(在活動(dòng)的) * */ private void drawActivRate(int position,Canvas canvas){ float radius = rateWidth/2;//根據(jù)每一個(gè)星星的位置繪製園,確定五角星五個(gè)點(diǎn)的位置 float angle = 360/5; float centerX = (rateWidth+padding)*(position+1)-padding-radius;//獲取每一個(gè)星星空間的中心位置的X坐標(biāo) float centerY =height/2;//獲取每一個(gè)星星空間的中心位置的y坐標(biāo) Path mPath = new Path(); mPath.moveTo(centerX,centerY-radius); mPath.lineTo(centerX+(float) Math.cos((angle*2-90)*Math.PI / 180)*radius,centerY+(float)Math.sin((angle*2-90)*Math.PI / 180)*radius); mPath.lineTo( centerX-(float)Math.sin(angle*Math.PI / 180)*radius,centerY-(float)Math.cos(angle*Math.PI / 180)*radius); mPath.lineTo( centerX+(float)Math.sin(angle*Math.PI / 180)*radius,centerY-(float)Math.cos(angle*Math.PI / 180)*radius); mPath.lineTo( centerX-(float)Math.sin((angle*3-180)*Math.PI / 180)*radius,centerY+(float)Math.cos((angle*3-180)*Math.PI / 180)*radius); // mPath.lineTo(centerX,centerY-radius); mPath.close(); canvas.drawPath(mPath,activPaint); } /** * 繪制灰色的五角星 * */ private void drawDisActivRate(int position,Canvas canvas){ float radius = rateWidth/2; float angle = 360/5; float centerX = (rateWidth+padding)*(position+1)-padding-radius; float centerY =height/2; Path mPath = new Path(); mPath.moveTo(centerX,centerY-radius); mPath.lineTo(centerX+(float) Math.cos((angle*2-90)*Math.PI / 180)*radius,centerY+(float)Math.sin((angle*2-90)*Math.PI / 180)*radius); mPath.lineTo( centerX-(float)Math.sin(angle*Math.PI / 180)*radius,centerY-(float)Math.cos(angle*Math.PI / 180)*radius); mPath.lineTo( centerX+(float)Math.sin(angle*Math.PI / 180)*radius,centerY-(float)Math.cos(angle*Math.PI / 180)*radius); mPath.lineTo( centerX-(float)Math.sin((angle*3-180)*Math.PI / 180)*radius,centerY+(float)Math.cos((angle*3-180)*Math.PI / 180)*radius); // mPath.lineTo(centerX,centerY-radius); mPath.close(); canvas.drawPath(mPath,disactivPaint); }
最后在onTouchEvent方法中處理選中和未選中星星的處理
@Override public boolean onTouchEvent(MotionEvent event) { if (!isTouch){//如果不支持觸摸 return false; } switch (event.getAction()) { case MotionEvent.ACTION_DOWN: touchX = event.getX(); touchY = event.getY(); for (int i = 0; i < size; i++) { if (i == 0) { if (0.0 < touchX && touchX < rateWidth+padding/2) { activeSize = 1; } }else { if ((rateWidth+padding)*i-padding/2<touchX&&touchX<(rateWidth+padding)*(i+1)-padding/2){ activeSize = i+1; } } } invalidate(); break; case MotionEvent.ACTION_UP: if ( null!= changeListener){ changeListener.change(activeSize); } break; case MotionEvent.ACTION_MOVE: touchX = event.getX(); touchY = event.getY(); for (int i = 0; i < size; i++) { if (i == 0) { if (0.0 < touchX && touchX < rateWidth+padding/2) { activeSize = 1; } }else { if ((rateWidth+padding)*i-padding/2<touchX&&touchX<(rateWidth+padding)*(i+1)-padding/2){ activeSize = i+1; } } } invalidate(); if (touchX<=0){ activeSize = 0; } break; } return true; }
以上就是自定義view寫(xiě)的星評(píng)控件,代碼中的注解已經(jīng)比較詳細(xì)了,就不多說(shuō)了,
源碼地址
以上所述是小編給大家介紹的android自定義星評(píng)空間的實(shí)例代碼,希望對(duì)大家有所幫助!
相關(guān)文章
android尺子的自定義view——RulerView詳解
這篇文章主要介紹了android尺子的自定義view——RulerView詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03Android中WebView圖片實(shí)現(xiàn)自適應(yīng)的方法
這篇文章主要介紹了Android中WebView圖片實(shí)現(xiàn)自適應(yīng)的方法,涉及Android操作圖片顯示的相關(guān)技巧,需要的朋友可以參考下2015-05-05Kotlin入門學(xué)習(xí)教程之可見(jiàn)性修飾符
在Kotlin中,不管是類、接口、構(gòu)造函數(shù)、函數(shù)、屬性及其設(shè)置器都具有可見(jiàn)性修飾符,下面這篇文章主要給大家介紹了關(guān)于Kotlin入門學(xué)習(xí)教程之可見(jiàn)性修飾符的相關(guān)資料,需要的朋友可以參考下2021-11-11Android獲得內(nèi)/外置存儲(chǔ)卡路徑的方法
我們知道Android上一般都有外置的存儲(chǔ)卡,內(nèi)置存儲(chǔ)卡路徑大家都知道怎么獲得的。那么如何獲取外置存儲(chǔ)卡的位置呢?下面小編通過(guò)本文給大家分享下2017-01-01Android OpenGL ES實(shí)現(xiàn)簡(jiǎn)單綠幕摳圖
這篇文章主要為大家介紹了Android OpenGL ES實(shí)現(xiàn)簡(jiǎn)單綠幕摳圖示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06Flutter配置代理抓包實(shí)現(xiàn)過(guò)程詳解
這篇文章主要為大家介紹了Flutter配置代理抓包實(shí)現(xiàn)過(guò)程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02Android Studio連接手機(jī)設(shè)備教程
這篇文章主要為大家詳細(xì)介紹了Android Studio連接手機(jī)設(shè)備教程,非常完整的連接步驟,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07Android實(shí)現(xiàn)二級(jí)列表購(gòu)物車功能
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)二級(jí)列表購(gòu)物車功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10