Android自定義View實(shí)現(xiàn)等級(jí)滑動(dòng)條的實(shí)例
Android自定義View實(shí)現(xiàn)等級(jí)滑動(dòng)條的實(shí)例
實(shí)現(xiàn)效果圖:

思路:
首先繪制直線,然后等分直線繪制點(diǎn);
繪制點(diǎn)的時(shí)候把X值存到集合中。
然后繪制背景圖片,以及圖片上的數(shù)字。
點(diǎn)擊事件down的時(shí)候,換小圖片為大圖片。move的時(shí)候跟隨手指移動(dòng)。
up的時(shí)候根據(jù)此時(shí)的X計(jì)算最近的集合中的點(diǎn),然后自動(dòng)吸附回去。
1,自定義屬性
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="BeautySeekBarView">
<attr name="valueCountent" format="integer"/>
<attr name="padding" format="dimension"/>
<attr name="pointColor" format="color"/>
<attr name="lineColor" format="color"/>
<attr name="smallPic" format="reference"/>
<attr name="bigPic" format="reference"/>
</declare-styleable>
</resources>
然后獲取屬性:
/**
* 獲得我們所定義的自定義樣式屬性
*/
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.BeautySeekBarView, defStyleAttr, 0);
//等級(jí)數(shù)量即點(diǎn)的個(gè)數(shù)
valueCountent=a.getInteger(R.styleable.BeautySeekBarView_valueCountent, 5);
//點(diǎn)的顏色
pointColor = a.getColor(R.styleable.BeautySeekBarView_pointColor, Color.WHITE);
//線的顏色
lineColor = a.getColor(R.styleable.BeautySeekBarView_lineColor, Color.WHITE);
//小圖片
smallPic=a.getResourceId(R.styleable.BeautySeekBarView_smallPic, R.drawable.ic_launcher);
//滑動(dòng)過(guò)程中的大圖片
bigPic=a.getResourceId(R.styleable.BeautySeekBarView_bigPic, R.drawable.ic_launcher);
//控件的內(nèi)邊距
viewPadding=a.getDimensionPixelSize(R.styleable.BeautySeekBarView_padding, (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
a.recycle();
2.繪制
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
float PointX = 0;
float PointY=getHeight()/2;
canvas.drawLine(0+getPaddingLeft(),PointY, getWidth()-getPaddingRight(), PointY, linePaint); //繪制直線
int averageLength =(getWidth()-getPaddingLeft()-getPaddingRight())/(valueCountent-1);
for(int i=0;i<valueCountent;i++){
PointX=i*averageLength+getPaddingLeft();
canvas.drawPoint(PointX, PointY, pointPaint);//繪制點(diǎn)
if(pointList!=null && pointList.size()<valueCountent){
pointList.add(PointX);//把每個(gè)點(diǎn)都放入集合中;
}
}
sePoolTH.release();
canvas.drawBitmap(mBitmap, bitmapPointX-bitmapWidth/2, PointY-bitmapHeight/2, null);//繪制拖動(dòng)的圖片
canvas.drawText(""+index, bitmapPointX, (getHeight() - fontMetrics.ascent - fontMetrics.descent) / 2, textPaint); //繪制文字
}
全部代碼如下
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.Semaphore;
import android.R.integer;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.FontMetricsInt;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
public class BeautySeekBarView extends View {
private Semaphore sePoolTH=new Semaphore(0);//信號(hào)量,解決并發(fā)問(wèn)題
private int valueCountent;//等級(jí)點(diǎn)的數(shù)量
private int pointColor;
private int lineColor;
private Bitmap mBitmap;
private int bitmapWidth;
private int bitmapHeight;
private float bitmapPointX;
private ArrayList<Float> pointList;//儲(chǔ)存畫(huà)出的點(diǎn)的point值
private HashMap<Float, Float> mHashMap;////把差值和listX當(dāng)做鍵值對(duì)保存起來(lái),便于后期找出
private int index=1;//索引
private float mListX;//移動(dòng)后最小的點(diǎn)
private int smallPic;
private int bigPic;
private int viewPadding;
private Paint pointPaint;
private Paint linePaint;
private Paint textPaint;
private FontMetricsInt fontMetrics;
public BeautySeekBarView(Context context) {
this(context,null);
}
public BeautySeekBarView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public BeautySeekBarView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
/**
* 獲得我們所定義的自定義樣式屬性
*/
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.BeautySeekBarView, defStyleAttr, 0);
//等級(jí)數(shù)量即點(diǎn)的個(gè)數(shù)
valueCountent=a.getInteger(R.styleable.BeautySeekBarView_valueCountent, 5);
//點(diǎn)的顏色
pointColor = a.getColor(R.styleable.BeautySeekBarView_pointColor, Color.WHITE);
//線的顏色
lineColor = a.getColor(R.styleable.BeautySeekBarView_lineColor, Color.WHITE);
//小圖片
smallPic=a.getResourceId(R.styleable.BeautySeekBarView_smallPic, R.drawable.ic_launcher);
//滑動(dòng)過(guò)程中的大圖片
bigPic=a.getResourceId(R.styleable.BeautySeekBarView_bigPic, R.drawable.ic_launcher);
//控件的內(nèi)邊距
viewPadding=a.getDimensionPixelSize(R.styleable.BeautySeekBarView_padding, (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
a.recycle();
initData();//初始化數(shù)據(jù)
initPaint();//初始化畫(huà)筆
}
public void initData() {
// valueCountent=7;
// pointColor=Color.WHITE;
// lineColor=Color.WHITE;
// setBackgroundColor(Color.BLACK);
setPadding(viewPadding, viewPadding, viewPadding, viewPadding);
bitmapPointX=getPaddingLeft();
mBitmap=BitmapFactory.decodeResource(getResources(), smallPic);
bitmapWidth=mBitmap.getWidth();
bitmapHeight=mBitmap.getHeight();
pointList=new ArrayList<Float>();
mHashMap=new HashMap<Float, Float>();
}
public void initPaint() {
pointPaint=new Paint();
pointPaint.setColor(pointColor);
pointPaint.setStyle(Paint.Style.FILL);
pointPaint.setStrokeWidth(10);
pointPaint.setStrokeJoin(Paint.Join.ROUND);
pointPaint.setStrokeCap(Paint.Cap.ROUND);
pointPaint.setAntiAlias(true);
linePaint=new Paint();
linePaint.setColor(lineColor);
linePaint.setStyle(Paint.Style.STROKE);
linePaint.setStrokeWidth(4);
linePaint.setAntiAlias(true);
textPaint=new Paint();
textPaint.setStrokeWidth(3);
textPaint.setTextSize(24);
textPaint.setColor(Color.WHITE);
textPaint.setTextAlign(Paint.Align.CENTER);
fontMetrics = textPaint.getFontMetricsInt();
textPaint.setAntiAlias(true);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
float PointX = 0;
float PointY=getHeight()/2;
canvas.drawLine(0+getPaddingLeft(),PointY, getWidth()-getPaddingRight(), PointY, linePaint); //繪制直線
int averageLength =(getWidth()-getPaddingLeft()-getPaddingRight())/(valueCountent-1);
for(int i=0;i<valueCountent;i++){
PointX=i*averageLength+getPaddingLeft();
canvas.drawPoint(PointX, PointY, pointPaint);//繪制點(diǎn)
if(pointList!=null && pointList.size()<valueCountent){
pointList.add(PointX);//把每個(gè)點(diǎn)都放入集合中;
}
}
sePoolTH.release();
canvas.drawBitmap(mBitmap, bitmapPointX-bitmapWidth/2, PointY-bitmapHeight/2, null);//繪制拖動(dòng)的圖片
canvas.drawText(""+index, bitmapPointX, (getHeight() - fontMetrics.ascent - fontMetrics.descent) / 2, textPaint); //繪制文字
}
long startTime = 0;
@Override
public boolean onTouchEvent(MotionEvent event) {
//獲取手指的操作--》按下、移動(dòng)、松開(kāi)
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
startTime=System.currentTimeMillis();
mBitmap=BitmapFactory.decodeResource(getResources(), bigPic);
bitmapWidth=mBitmap.getWidth();
bitmapHeight=mBitmap.getHeight();
textPaint.setTextSize(30);
//invalidate();
break;
case MotionEvent.ACTION_MOVE:
long endTimeMove=System.currentTimeMillis();
if(endTimeMove-startTime>100){//如果按下,抬起時(shí)間過(guò)大才認(rèn)為是拖動(dòng),要執(zhí)行動(dòng)畫(huà)。
bitmapPointX=event.getX();
updateIndex(bitmapPointX);
invalidate();
}
break;
case MotionEvent.ACTION_UP:
long endTime=System.currentTimeMillis();
bitmapPointX=event.getX();
mBitmap=BitmapFactory.decodeResource(getResources(),smallPic);
bitmapWidth=mBitmap.getWidth();
bitmapHeight=mBitmap.getHeight();
textPaint.setTextSize(24);
if(endTime-startTime>200){//如果按下,抬起時(shí)間過(guò)大才認(rèn)為是拖動(dòng),要執(zhí)行動(dòng)畫(huà)。
updateBitmapUI(bitmapPointX);
}else{
bitmapPointX=updateIndex(bitmapPointX);
invalidate();
}
startTime = 0;
break;
}
return true;
}
//更新索引
public float updateIndex(float pointX){
float lastValue=100000;
float currentValue=0;
float minValue=0;
for(float listX:pointList){
currentValue= Math.abs(pointX-listX);
mHashMap.put(currentValue, listX);//把差值和listX當(dāng)做鍵值對(duì)保存起來(lái),便于后期找出
minValue=Math.min(lastValue,currentValue);
lastValue=minValue;
}
if(mHashMap.containsKey(minValue)){
mListX=mHashMap.get(minValue);
}else{
Log.e("BeautySeekBarView", "updateBitmapUI--->mHashMap.containsKey(minValue) is null");
return -1;
}
if(pointList.contains(mListX)){
index=pointList.indexOf(mListX)+1;
if(mListener!=null){
mListener.getIndex(index);
}
}else{
Log.e("BeautySeekBarView", "updateBitmapUI--->pointList.contains(mListX) is null");
return -1;
}
return mListX;
}
//當(dāng)手指抬起后更新Bitmap的位置
private void updateBitmapUI(float PointX2) {
mListX=updateIndex(PointX2);
//執(zhí)行動(dòng)畫(huà)
ValueAnimator anim = ValueAnimator.ofFloat(PointX2, mListX);
anim.setDuration(50);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
bitmapPointX =(Float) animation.getAnimatedValue();
invalidate();
}
});
anim.start();
}
//設(shè)置等級(jí)點(diǎn)的數(shù)量
public void pointValueCountent(int countent){
if(countent<2){
valueCountent=2;
}else{
valueCountent=countent;
}
invalidate();
}
//設(shè)置默認(rèn)位置
public void setPointLocation(final int location){
new Thread(new Runnable() {
@Override
public void run() {
try {
sePoolTH.acquire();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(location>0&&pointList!=null&& !pointList.isEmpty()){
bitmapPointX=pointList.get(location-1);
postInvalidate();
}
}
}).start();
}
//提供接口回調(diào),獲取索引
private indexListener mListener=null;
public interface indexListener{
void getIndex(int index);
}
public void setIndexListener(indexListener listener){
mListener=listener;
}
}
外部調(diào)用:
XML:
<com.example.hello.BeautySeekBarView
android:id="@+id/myView"
android:layout_centerVertical="true"
android:layout_width="match_parent"
android:layout_height="100dp"
ws:padding="20dp"
ws:valueCountent="6"
ws:pointColor="#FFFFFF"
ws:lineColor="#FFFFFF"
ws:smallPic="@drawable/beauty_seekbar_point"
ws:bigPic="@drawable/beauty_seekbar_point_big"/>
Java:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
beautySeekBarView.setPointLocation(2) ;
//
}
private void initView() {
mTextView=(TextView) findViewById(R.id.tv);
beautySeekBarView=(BeautySeekBarView) findViewById(R.id.myView);
beautySeekBarView.setIndexListener(new indexListener() {
@Override
public void getIndex(int index) {
mTextView.setText("index="+index);
}
});
}
感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
- Android應(yīng)用開(kāi)發(fā)SharedPreferences存儲(chǔ)數(shù)據(jù)的使用方法
- android TextView設(shè)置中文字體加粗實(shí)現(xiàn)方法
- android調(diào)試工具DDMS的使用詳解
- Android Bitmap詳細(xì)介紹
- Android的Activity跳轉(zhuǎn)動(dòng)畫(huà)各種效果整理
- android listview優(yōu)化幾種寫(xiě)法詳細(xì)介紹
- 解決Android SDK下載和更新失敗的方法詳解
- Android SQLite數(shù)據(jù)庫(kù)增刪改查操作的使用詳解
相關(guān)文章
Android實(shí)現(xiàn)類(lèi)似360,QQ管家那樣的懸浮窗
用到的就是WindowManager以及WindowManager.LayoutParams,對(duì)這個(gè)LayoutParams做文章,當(dāng)設(shè)置為屬性后,然后,創(chuàng)建一個(gè)View,將這個(gè)View添加到WindowManager中就行2013-06-06
Android啟動(dòng)頁(yè)面定時(shí)跳轉(zhuǎn)的三種方法
這篇文章主要介紹了Android啟動(dòng)頁(yè)面定時(shí)跳轉(zhuǎn)的三種方法,實(shí)現(xiàn)打開(kāi)一個(gè)Android手機(jī)APP的歡迎界面后跳轉(zhuǎn)到指定界面的效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11
Android利用ScaleTransition實(shí)現(xiàn)吹氣球動(dòng)畫(huà)
這篇文章主要為大家介紹了如何將利用ScaleTransition實(shí)現(xiàn)一個(gè)吹氣球的動(dòng)畫(huà),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下2022-04-04
ImageView的屬性android:scaleType的作用分析
本篇文章是對(duì)ImageView的屬性android:scaleType的作用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06
Android實(shí)現(xiàn)可拖拽的GridView效果長(zhǎng)按可拖拽刪除數(shù)據(jù)源
這篇文章主要介紹了Android實(shí)現(xiàn)可拖拽的GridView效果長(zhǎng)按可拖拽刪除數(shù)據(jù)源,要實(shí)現(xiàn)的基本功能是長(zhǎng)按,移到垃圾桶,刪除數(shù)據(jù),需要的朋友可以參考下2017-12-12
Android開(kāi)發(fā)筆記之:AsyncTask的應(yīng)用詳解
本篇文章是對(duì)Android中AsyncTask的應(yīng)用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
Android游戲開(kāi)發(fā)學(xué)習(xí)之引擎用法實(shí)例詳解
這篇文章主要介紹了Android游戲開(kāi)發(fā)學(xué)習(xí)之引擎用法,較為詳細(xì)的分析了Android游戲開(kāi)發(fā)中所常用的JBox2D引擎功能及相關(guān)使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10
Android開(kāi)發(fā)之圖片壓縮實(shí)現(xiàn)方法分析
這篇文章主要介紹了Android開(kāi)發(fā)之圖片壓縮實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了Android圖片壓縮的原理、實(shí)現(xiàn)方法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下2019-03-03
Android實(shí)現(xiàn)圓角Button按鈕
這篇文章主要介紹了Android實(shí)現(xiàn)圓角Button按鈕,利用xml文件中 shape實(shí)現(xiàn)圓角效果,感興趣的小伙伴們可以參考一下2015-12-12

