Android——自定义带刻度的SeekBar单向拖动条
时间过得真快,才发现好久没来逛逛了。没写博客的这段时间一直在做项目,连续完成了两个大型app,这个过程很享受,这是独立开发的,所以中途有很多很多的问题需要自己一个一个的去解决,现在接近尾声了,发现自己在这个阶段成长了不少,当然需要学习的知识还有很多很多,就让我们大家一起学习吧!
今天就分享一个自己在项目中,客户要求的功能,拖动条设置ListView列表中item的金额。这边主要的就是说seekbar这个东西,那我们开始吧!
看下效果:
大概就是这样,上面的刻度值是可以动态设置的,下面详细说一下,先看下自定义的代码块:
package com.ds.platform.view;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.TypeEvaluator;
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.Matrix;
import android.graphics.NinePatch;
import android.graphics.Paint;
import android.graphics.RadialGradient;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.Typeface;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import com.ds.platform.R;
import com.ds.platform.utils.SharePreferencesUtils;
/**
* @author: Allen
* @date: 2017/3/13
* @description: 自定义SeekBar 带刻度
*/
public class RangeSeekBar extends View {
private static final float DEFAULT_RADIUS = 0.5f;
//default seekbar's padding left and right
private int DEFAULT_PADDING_LEFT_AND_RIGHT;
private int defaultPaddingTop;
//进度提示的背景 The background of the progress
private final int mProgressHintBGId;
// 按钮的背景 The background of the Drag button
private final int mThumbResId;
//刻度模式:number根据数字实际比例排列;other 均分排列
//Scale mode:
// number according to the actual proportion of the number of arranged;
// other equally arranged
private final int mCellMode;
//single是Seekbar模式,range是RangeSeekbar
//single is Seekbar mode, range is angeSeekbar
//single = 1; range = 2
private final int mSeekBarMode;
//默认为1,当大于1时自动切回刻度模式
//The default is 1, and when it is greater than 1,
// it will automatically switch back to the scale mode
private int cellsCount = 1;
//刻度与进度条间的间距
//The spacing between the scale and the progress bar
private int textPadding;
//进度提示背景与按钮之间的距离
//The progress indicates the distance between the background and the button
private int mHintBGPadding;
private int mSeekBarHeight;
private int mThumbSize;
//两个按钮之间的最小距离
//The minimum distance between two buttons
private int reserveCount;
private int mCursorTextHeight;
private int mPartLength;
private int heightNeeded;
private int lineCorners;
private int lineWidth;
//选择过的进度条颜色
// the color of the selected progress bar
private int colorLineSelected;
//未选则的进度条颜色
// the color of the unselected progress bar
private int colorLineEdge;
//The foreground color of progress bar and thumb button.
private int colorPrimary;
//The background color of progress bar and thumb button.
private int colorSecondary;
//刻度文字与提示文字的大小
//Scale text and prompt text size
private int mTextSize;
private int mTextColor;
private int lineTop, lineBottom, lineLeft, lineRight;
//进度提示背景的高度,宽度如果是0的话会自适应调整
//Progress prompted the background height, width,
// if it is 0, then adaptively adjust
private float mHintBGHeight;
private float mHintBGWith;
private float offsetValue;
private float cellsPercent;
private float reserveValue;
private float reservePercent;
private float maxValue, minValue;
//真实的最大值和最小值
//True maximum and minimum values
private float mMin, mMax;
private boolean isEnable = true;
private final boolean mHideProgressHint;
//刻度上显示的文字
private CharSequence[] mTextArray;
private Bitmap mProgressHintBG;
private Paint mMainPaint = new Paint();
private Paint mCursorPaint = new Paint();
private Paint mProgressPaint;
private RectF line = new RectF();
private SeekBar leftSB;
private SeekBar rightSB;
private SeekBar currTouch;
private OnRangeChangedListener callback;
public RangeSeekBar(Context context) {
this(context, null);
}
public RangeSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray t = context.obtainStyledAttributes(attrs, R.styleable.RangeSeekBar);
cellsCount = t.getInt(R.styleable.RangeSeekBar_cells, 1);
reserveValue = t.getFloat(R.styleable.RangeSeekBar_reserve, 0);
mMin = t.getFloat(R.styleable.RangeSeekBar_min, 0);//最小取值
//从缓存中拿值
float maxValue = SharePreferencesUtils.getFloat(context, "maxValue", 0);
if (0 == maxValue) {
mMax = t.getFloat(R.styleable.RangeSeekBar_max, 100);//最大取值
} else {
mMax = maxValue;
}
mThumbResId = t.getResourceId(R.styleable.RangeSeekBar_seekBarResId, 0);
mProgressHintBGId = t.getResourceId(R.styleable.RangeSeekBar_progressHintResId, 0);
colorLineSelected = t.getColor(R.styleable.RangeSeekBar_lineColorSelected, 0xFF4BD962);
colorLineEdge = t.getColor(R.styleable.RangeSeekBar_lineColorEdge, 0xFF0000);
colorPrimary = t.getColor(R.styleable.RangeSeekBar_thumbPrimaryColor, 0);
colorSecondary = t.getColor(R.styleable.RangeSeekBar_thumbSecondaryColor, 0);
//从缓存中拿值
CharSequence tempArray[] = SharePreferencesUtils.getStringSet(context, "textArray", null);
if (tempArray == null || tempArray.length == 0) {
mTextArray = t.getTextArray(R.styleable.RangeSeekBar_markTextArray);
} else {
mTextArray = tempArray;
}
mHideProgressHint = t.getBoolean(R.styleable.RangeSeekBar_hideProgressHint, false);
textPadding = (int) t.getDimension(R.styleable.RangeSeekBar_textPadding, dp2px(context, 20));
mTextSize = (int) t.getDimension(R.styleable.RangeSeekBar_textSize, dp2px(context, 12));
mTextColor = t.getColor(R.styleable.RangeSeekBar_textColor, ContextCompat.getColor(context, R.color.main_text));
mHintBGHeight = t.getDimension(R.styleable.RangeSeekBar_hintBGHeight, 0);
mHintBGWith = t.getDimension(R.styleable.RangeSeekBar_hintBGWith, 0);
mSeekBarHeight = (int) t.getDimension(R.styleable.RangeSeekBar_seekBarHeight, dp2px(context, 2));
mHintBGPadding = (int) t.getDimension(R.styleable.RangeSeekBar_hintBGPadding, 0);
mThumbSize = (int) t.getDimension(R.styleable.RangeSeekBar_thumbSize, dp2px(context, 26));
mCellMode = t.getInt(R.styleable.RangeSeekBar_cellMode, 0);
mSeekBarMode = t.getInt(R.styleable.RangeSeekBar_seekBarMode, 2);
if (mSeekBarMode == 2) {
leftSB = new SeekBar(-1);
rightSB = new SeekBar(1);
} else {
leftSB = new SeekBar(-1);
}
// if you don't set the mHintBGWith or the mHintBGWith < default value, if will use default value
if (mHintBGWith == 0) {
DEFAULT_PADDING_LEFT_AND_RIGHT = dp2px(context, 25);
} else {
DEFAULT_PADDING_LEFT_AND_RIGHT = Math.max((int) (mHintBGWith / 2 + dp2px(context, 5)), dp2px(context, 25));
}
setRules(mMin, mMax, reserveValue, cellsCount);
initPaint();
initBitmap();
t.recycle();
defaultPaddingTop = mSeekBarHeight / 2;
mHintBGHeight = mHintBGHeight == 0 ? (mCursorPaint.measureText("国") * 3) : mHintBGHeight;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
heightNeeded = 2 * (lineTop) + mSeekBarHeight;
/**
* onMeasure传入的widthMeasureSpec和heightMeasureSpec不是一般的尺寸数值,而是将模式和尺寸组合在一起的数值
* MeasureSpec.EXACTLY 是精确尺寸
* MeasureSpec.AT_MOST 是最大尺寸
* MeasureSpec.UNSPECIFIED 是未指定尺寸
*/
if (heightMode == MeasureSpec.EXACTLY) {
heightSize = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY);
} else if (heightMode == MeasureSpec.AT_MOST) {
heightSize = MeasureSpec.makeMeasureSpec(
heightSize < heightNeeded ? heightSize : heightNeeded, MeasureSpec.EXACTLY);
} else {
heightSize = MeasureSpec.makeMeasureSpec(
heightNeeded, MeasureSpec.EXACTLY);
}
super.onMeasure(widthMeasureSpec, heightSize);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//计算进度条的位置,并根据它初始化两个按钮的位置
// Calculates the position of the progress bar and initializes the positions of
// the two buttons based on it
lineLeft = DEFAULT_PADDING_LEFT_AND_RIGHT + getPaddingLeft();
lineRight = w - lineLeft - getPaddingRight();
lineTop = (int) mHintBGHeight + mThumbSize / 2 - mSeekBarHeight / 2 + 30;
lineBottom = lineTop + mSeekBarHeight;
lineWidth = lineRight - lineLeft;
line.set(lineLeft, lineTop, lineRight, lineBottom);
lineCorners = (int) ((lineBottom - lineTop) * 0.45f);
leftSB.onSizeChanged(lineLeft, lineBottom, mThumbSize, lineWidth, cellsCount > 1, mThumbResId, getContext());
if (mSeekBarMode == 2) {
rightSB.onSizeChanged(lineLeft, lineBottom, mThumbSize, lineWidth, cellsCount > 1, mThumbResId, getContext());
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制刻度,并且根据当前位置是否在刻度范围内设置不同的颜色显示
// Draw the scales, and according to the current position is set within
// the scale range of different color display
if (mTextArray != null) {
mPartLength = lineWidth / (mTextArray.length - 1);
for (int i = 0; i < mTextArray.length; i++) {
final String text2Draw = mTextArray[i].toString();
float x;
//平分显示
if (mCellMode == 1) {
mCursorPaint.setColor(mTextColor);
mCursorPaint.setAntiAlias(true);
x = lineLeft + i * mPartLength - mCursorPaint.measureText(text2Draw) / 2;
} else {
float num = Float.parseFloat(text2Draw);
float[] result = getCurrentRange();
if (compareFloat(num, result[0]) != -1 && compareFloat(num, result[1]) != 1 && mSeekBarMode == 2) {
mCursorPaint.setColor(ContextCompat.getColor(getContext(), R.color.colorAccent));
} else {
mCursorPaint.setColor(mTextColor);
mCursorPaint.setAntiAlias(true);
}
//按实际比例显示
x = lineLeft + lineWidth * (num - mMin) / (mMax - mMin)
- mCursorPaint.measureText(text2Draw) / 2;
}
float y = lineTop - textPadding;
canvas.drawText(text2Draw, x, y, mCursorPaint);
}
}
//绘制进度条
// draw the progress bar
mMainPaint.setColor(colorLineEdge);
canvas.drawRoundRect(line, lineCorners, lineCorners, mMainPaint);
mMainPaint.setColor(colorLineSelected);
if (mSeekBarMode == 2) {
canvas.drawRect(leftSB.left + leftSB.widthSize / 2 + leftSB.lineWidth * leftSB.currPercent, lineTop,
rightSB.left + rightSB.widthSize / 2 + rightSB.lineWidth * rightSB.currPercent, lineBottom, mMainPaint);
} else {
canvas.drawRect(leftSB.left + leftSB.widthSize / 2, lineTop,
leftSB.left + leftSB.widthSize / 2 + leftSB.lineWidth * leftSB.currPercent, lineBottom, mMainPaint);
}
leftSB.draw(canvas);
if (mSeekBarMode == 2) {
rightSB.draw(canvas);
}
}
/**
* 初始化画笔
* init the paints
*/
private void initPaint() {
mMainPaint.setStyle(Paint.Style.FILL);
mMainPaint.setColor(colorLineEdge);
mCursorPaint.setStyle(Paint.Style.FILL);
mCursorPaint.setColor(colorLineEdge);
mCursorPaint.setTextSize(mTextSize);
mProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mProgressPaint.setTypeface(Typeface.DEFAULT);
mProgressPaint.setColor(0xFF0000);
//计算文字的高度
//Calculate the height of the text
Paint.FontMetrics fm = mCursorPaint.getFontMetrics();
mCursorTextHeight = (int) (Math.ceil(fm.descent - fm.ascent) + 2);
}
/**
* 初始化进度提示的背景
*/
private void initBitmap() {
if (mProgressHintBGId != 0) {
mProgressHintBG = BitmapFactory.decodeResource(getResources(), mProgressHintBGId);
} else {
mProgressHintBG = BitmapFactory.decodeResource(getResources(), R.drawable.progress_hint_bg);
}
}
//*********************************** SeekBar ***********************************//
private class SeekBar {
private int lineWidth;
private int widthSize, heightSize;
private int left, right, top, bottom;
private float currPercent;
private float material = 0;
public boolean isShowingHint;
private boolean isLeft;
private Bitmap bmp;
private ValueAnimator anim;
private RadialGradient shadowGradient;
private Paint defaultPaint;
private String mHintText2Draw;
private Boolean isPrimary = true;
public SeekBar(int position) {
if (position < 0) {
isLeft = true;
} else {
isLeft = false;
}
}
/**
* 计算每个按钮的位置和尺寸
* Calculates the position and size of each button
*
* @param x
* @param y
* @param hSize
* @param parentLineWidth
* @param cellsMode
* @param bmpResId
* @param context
*/
protected void onSizeChanged(int x, int y, int hSize, int parentLineWidth, boolean cellsMode, int bmpResId, Context context) {
heightSize = hSize;
widthSize = heightSize;
left = x - widthSize / 2;
right = x + widthSize / 2;
top = y - heightSize / 2;
bottom = y + heightSize / 10;
if (cellsMode) {
lineWidth = parentLineWidth;
} else {
lineWidth = parentLineWidth;
}
if (bmpResId > 0) {
Bitmap original = BitmapFactory.decodeResource(context.getResources(), bmpResId);
if (original != null) {
Matrix matrix = new Matrix();
float scaleHeight = mThumbSize * 1.0f / original.getHeight();
float scaleWidth = scaleHeight;
matrix.postScale(scaleWidth, scaleHeight);
bmp = Bitmap.createBitmap(original, 0, 0, original.getWidth(), original.getHeight(), matrix, true);
}
} else {
defaultPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
int radius = (int) (widthSize * DEFAULT_RADIUS);
int barShadowRadius = (int) (radius * 0.95f);
int mShadowCenterX = widthSize / 2;
int mShadowCenterY = heightSize / 2;
shadowGradient = new RadialGradient(mShadowCenterX, mShadowCenterY, barShadowRadius, Color.BLACK, Color.TRANSPARENT, Shader.TileMode.CLAMP);
}
}
/**
* 绘制按钮和提示背景和文字
* Draw buttons and tips for background and text
*
* @param canvas
*/
protected void draw(Canvas canvas) {
int offset = (int) (lineWidth * currPercent);
canvas.save();
canvas.translate(offset, 0);
String text2Draw = "";
int hintW = 0, hintH = 0;
float[] result = getCurrentRange();
if (mHideProgressHint) {
isShowingHint = false;
} else {
if (isLeft) {
if (mHintText2Draw == null) {
text2Draw = (int) result[0] + "";
} else {
text2Draw = mHintText2Draw;
}
// if is the start,change the thumb color
isPrimary = (compareFloat(result[0], mMin) == 0);
} else {
if (mHintText2Draw == null) {
text2Draw = (int) result[1] + "";
} else {
text2Draw = mHintText2Draw;
}
isPrimary = (compareFloat(result[1], mMax) == 0);
}
hintH = (int) mHintBGHeight - 20;//设置提示背景的高度
hintW = (int) (mHintBGWith == 0 ? (mCursorPaint.measureText(text2Draw) + DEFAULT_PADDING_LEFT_AND_RIGHT)
: mHintBGWith);
if (hintW < 1.5f * hintH) hintW = (int) (1.5f * hintH);
}
if (bmp != null) {
canvas.drawBitmap(bmp, left, lineTop - bmp.getHeight() / 2, null);
if (isShowingHint) {
Rect rect = new Rect();
rect.left = left - (hintW / 2 - bmp.getWidth() / 2);
rect.top = bottom - hintH - bmp.getHeight();
rect.right = rect.left + hintW;
rect.bottom = rect.top + hintH - 10;
drawNinePath(canvas, mProgressHintBG, rect);
mCursorPaint.setColor(Color.WHITE);//提示字的颜色
mCursorPaint.setTextSize(mTextSize);
int x = (int) (left + (bmp.getWidth() / 2) - mCursorPaint.measureText(text2Draw) / 2);
int y = bottom - hintH - bmp.getHeight() + hintH / 2;
canvas.drawText(text2Draw, x, y, mCursorPaint);
}
} else {
canvas.translate(left, 0);
if (isShowingHint) {
Rect rect = new Rect();
rect.left = widthSize / 2 - hintW / 2;
rect.top = defaultPaddingTop;
rect.right = rect.left + hintW;
rect.bottom = rect.top + hintH - 10;
drawNinePath(canvas, mProgressHintBG, rect);
mCursorPaint.setColor(Color.WHITE);
mCursorPaint.setTextSize(mTextSize);
int x = (int) (widthSize / 2 - mCursorPaint.measureText(text2Draw) / 2);
// TODO: 2017/2/6
//这里和背景形状有关,暂时根据本图形状比例计算
//Here and the background shape, temporarily based on the shape of this figure ratio calculation
int y = hintH / 3 + defaultPaddingTop + mCursorTextHeight / 2;
canvas.drawText(text2Draw, x, y, mCursorPaint);
}
drawDefault(canvas);
}
canvas.restore();
}
/**
* 绘制 9Path
*
* @param c
* @param bmp
* @param rect
*/
public void drawNinePath(Canvas c, Bitmap bmp, Rect rect) {
NinePatch patch = new NinePatch(bmp, bmp.getNinePatchChunk(), null);
patch.draw(c, rect);
}
/**
* 如果没有图片资源,则绘制默认按钮
* <p>
* If there is no image resource, draw the default button
*
* @param canvas
*/
private void drawDefault(Canvas canvas) {
int centerX = widthSize / 2;
int centerY = lineBottom - mSeekBarHeight / 2;
int radius = (int) (widthSize * DEFAULT_RADIUS);
// draw shadow
defaultPaint.setStyle(Paint.Style.FILL);
canvas.save();
canvas.translate(0, radius * 0.25f);
canvas.scale(1 + (0.1f * material), 1 + (0.1f * material), centerX, centerY);
defaultPaint.setShader(shadowGradient);
canvas.drawCircle(centerX, centerY, radius, defaultPaint);
defaultPaint.setShader(null);
canvas.restore();
// draw body
defaultPaint.setStyle(Paint.Style.FILL);
if (isPrimary) {
//if not set the color,it will use default color
if (colorPrimary == 0) {
defaultPaint.setColor(te.evaluate(material, 0xFFFFFFFF, 0xFFE7E7E7));
} else {
defaultPaint.setColor(colorPrimary);
}
} else {
if (colorSecondary == 0) {
defaultPaint.setColor(te.evaluate(material, 0xFFFFFFFF, 0xFF0000));
} else {
defaultPaint.setColor(colorSecondary);
}
}
canvas.drawCircle(centerX, centerY, radius, defaultPaint);
// draw border
defaultPaint.setStyle(Paint.Style.STROKE);
defaultPaint.setColor(0xFFD7D7D7);
canvas.drawCircle(centerX, centerY, radius, defaultPaint);
}
final TypeEvaluator<Integer> te = new TypeEvaluator<Integer>() {
@Override
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int alpha = (int) (Color.alpha(startValue) + fraction * (Color.alpha(endValue) - Color.alpha(startValue)));
int red = (int) (Color.red(startValue) + fraction * (Color.red(endValue) - Color.red(startValue)));
int green = (int) (Color.green(startValue) + fraction * (Color.green(endValue) - Color.green(startValue)));
int blue = (int) (Color.blue(startValue) + fraction * (Color.blue(endValue) - Color.blue(startValue)));
return Color.argb(alpha, red, green, blue);
}
};
/**
* 拖动检测
*
* @param event
* @return
*/
protected boolean collide(MotionEvent event) {
float x = event.getX();
float y = event.getY();
int offset = (int) (lineWidth * currPercent);
return x > left + offset && x < right + offset && y > top && y < bottom;
}
private void slide(float percent) {
if (percent < 0) percent = 0;
else if (percent > 1) percent = 1;
currPercent = percent;
}
private void materialRestore() {
if (anim != null) anim.cancel();
anim = ValueAnimator.ofFloat(material, 0);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
material = (float) animation.getAnimatedValue();
invalidate();
}
});
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
material = 0;
invalidate();
}
});
anim.start();
}
public void setProgressHint(String hint) {
mHintText2Draw = hint;
}
}
//*********************************** SeekBar ***********************************//
public interface OnRangeChangedListener {
void onRangeChanged(RangeSeekBar view, float min, float max, boolean isFromUser);
}
public void setOnRangeChangedListener(OnRangeChangedListener listener) {
callback = listener;
}
public void setValue(float min, float max) {
min = min + offsetValue;
max = max + offsetValue;
if (min < minValue) {
throw new IllegalArgumentException("setValue() min < (preset min - offsetValue) . #min:" + min + " #preset min:" + minValue + " #offsetValue:" + offsetValue);
}
if (max > maxValue) {
throw new IllegalArgumentException("setValue() max > (preset max - offsetValue) . #max:" + max + " #preset max:" + maxValue + " #offsetValue:" + offsetValue);
}
if (reserveCount > 1) {
if ((min - minValue) % reserveCount != 0) {
throw new IllegalArgumentException("setValue() (min - preset min) % reserveCount != 0 . #min:" + min + " #preset min:" + minValue + "#reserveCount:" + reserveCount + "#reserve:" + reserveValue);
}
if ((max - minValue) % reserveCount != 0) {
throw new IllegalArgumentException("setValue() (max - preset min) % reserveCount != 0 . #max:" + max + " #preset min:" + minValue + "#reserveCount:" + reserveCount + "#reserve:" + reserveValue);
}
leftSB.currPercent = (min - minValue) / reserveCount * cellsPercent;
if (mSeekBarMode == 2) {
rightSB.currPercent = (max - minValue) / reserveCount * cellsPercent;
}
} else {
leftSB.currPercent = (min - minValue) / (maxValue - minValue);
if (mSeekBarMode == 2) {
rightSB.currPercent = (max - minValue) / (maxValue - minValue);
}
}
if (callback != null) {
if (mSeekBarMode == 2) {
callback.onRangeChanged(this, leftSB.currPercent, rightSB.currPercent, false);
} else {
callback.onRangeChanged(this, leftSB.currPercent, leftSB.currPercent, false);
}
}
invalidate();
}
public void setValue(float value) {
setValue(value, mMax);
}
public void setRange(float min, float max) {
setRules(min, max, reserveCount, cellsCount);
}
public void setRules(float min, float max, float reserve, int cells) {
if (max <= min) {
throw new IllegalArgumentException("setRules() max must be greater than min ! #max:" + max + " #min:" + min);
}
mMax = max;
mMin = min;
if (min < 0) {
offsetValue = 0 - min;
min = min + offsetValue;
max = max + offsetValue;
}
minValue = min;
maxValue = max;
if (reserve < 0) {
throw new IllegalArgumentException("setRules() reserve must be greater than zero ! #reserve:" + reserve);
}
if (reserve >= max - min) {
throw new IllegalArgumentException("setRules() reserve must be less than (max - min) ! #reserve:" + reserve + " #max - min:" + (max - min));
}
if (cells < 1) {
throw new IllegalArgumentException("setRules() cells must be greater than 1 ! #cells:" + cells);
}
cellsCount = cells;
cellsPercent = 1f / cellsCount;
reserveValue = reserve;
reservePercent = reserve / (max - min);
reserveCount = (int) (reservePercent / cellsPercent + (reservePercent % cellsPercent != 0 ? 1 : 0));
if (cellsCount > 1) {
if (mSeekBarMode == 2) {
if (leftSB.currPercent + cellsPercent * reserveCount <= 1 && leftSB.currPercent + cellsPercent * reserveCount > rightSB.currPercent) {
rightSB.currPercent = leftSB.currPercent + cellsPercent * reserveCount;
} else if (rightSB.currPercent - cellsPercent * reserveCount >= 0 && rightSB.currPercent - cellsPercent * reserveCount < leftSB.currPercent) {
leftSB.currPercent = rightSB.currPercent - cellsPercent * reserveCount;
}
} else {
if (1 - cellsPercent * reserveCount >= 0 && 1 - cellsPercent * reserveCount < leftSB.currPercent) {
leftSB.currPercent = 1 - cellsPercent * reserveCount;
}
}
} else {
if (mSeekBarMode == 2) {
if (leftSB.currPercent + reservePercent <= 1 && leftSB.currPercent + reservePercent > rightSB.currPercent) {
rightSB.currPercent = leftSB.currPercent + reservePercent;
} else if (rightSB.currPercent - reservePercent >= 0 && rightSB.currPercent - reservePercent < leftSB.currPercent) {
leftSB.currPercent = rightSB.currPercent - reservePercent;
}
} else {
if (1 - reservePercent >= 0 && 1 - reservePercent < leftSB.currPercent) {
leftSB.currPercent = 1 - reservePercent;
}
}
}
invalidate();
}
public float getMax() {
return mMax;
}
public float getMin() {
return mMin;
}
public float[] getCurrentRange() {
float range = maxValue - minValue;
if (mSeekBarMode == 2) {
return new float[]{-offsetValue + minValue + range * leftSB.currPercent,
-offsetValue + minValue + range * rightSB.currPercent};
} else {
return new float[]{-offsetValue + minValue + range * leftSB.currPercent,
-offsetValue + minValue + range * 1.0f};
}
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
this.isEnable = enabled;
}
public void setProgressDescription(String progress) {
if (leftSB != null) {
leftSB.setProgressHint(progress);
}
if (rightSB != null) {
rightSB.setProgressHint(progress);
}
}
public void setLeftProgressDescription(String progress) {
if (leftSB != null) {
leftSB.setProgressHint(progress);
}
}
public void setRightProgressDescription(String progress) {
if (rightSB != null) {
rightSB.setProgressHint(progress);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnable) return true;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
boolean touchResult = false;
if (rightSB != null && rightSB.currPercent >= 1 && leftSB.collide(event)) {
currTouch = leftSB;
touchResult = true;
} else if (rightSB != null && rightSB.collide(event)) {
currTouch = rightSB;
touchResult = true;
} else if (leftSB.collide(event)) {
currTouch = leftSB;
touchResult = true;
}
//Intercept parent TouchEvent
if (getParent() != null) {
getParent().requestDisallowInterceptTouchEvent(true);
}
return touchResult;
case MotionEvent.ACTION_MOVE:
float percent;
float x = event.getX();
currTouch.material = currTouch.material >= 1 ? 1 : currTouch.material + 0.1f;
if (currTouch == leftSB) {
if (cellsCount > 1) {
if (x < lineLeft) {
percent = 0;
} else {
percent = (x - lineLeft) * 1f / (lineWidth);
}
int touchLeftCellsValue = Math.round(percent / cellsPercent);
int currRightCellsValue;
if (mSeekBarMode == 2) {
currRightCellsValue = Math.round(rightSB.currPercent / cellsPercent);
} else {
currRightCellsValue = Math.round(1.0f / cellsPercent);
}
percent = touchLeftCellsValue * cellsPercent;
while (touchLeftCellsValue > currRightCellsValue - reserveCount) {
touchLeftCellsValue--;
if (touchLeftCellsValue < 0) break;
percent = touchLeftCellsValue * cellsPercent;
}
} else {
if (x < lineLeft) {
percent = 0;
} else {
percent = (x - lineLeft) * 1f / (lineWidth);
}
if (mSeekBarMode == 2) {
if (percent > rightSB.currPercent - reservePercent) {
percent = rightSB.currPercent - reservePercent;
}
} else {
if (percent > 1.0f - reservePercent) {
percent = 1.0f - reservePercent;
}
}
}
leftSB.slide(percent);
leftSB.isShowingHint = true;
//Intercept parent TouchEvent
if (getParent() != null) {
getParent().requestDisallowInterceptTouchEvent(true);
}
} else if (currTouch == rightSB) {
if (cellsCount > 1) {
if (x > lineRight) {
percent = 1;
} else {
percent = (x - lineLeft) * 1f / (lineWidth);
}
int touchRightCellsValue = Math.round(percent / cellsPercent);
int currLeftCellsValue = Math.round(leftSB.currPercent / cellsPercent);
percent = touchRightCellsValue * cellsPercent;
while (touchRightCellsValue < currLeftCellsValue + reserveCount) {
touchRightCellsValue++;
if (touchRightCellsValue > maxValue - minValue) break;
percent = touchRightCellsValue * cellsPercent;
}
} else {
if (x > lineRight) {
percent = 1;
} else {
percent = (x - lineLeft) * 1f / (lineWidth);
}
if (percent < leftSB.currPercent + reservePercent) {
percent = leftSB.currPercent + reservePercent;
}
}
rightSB.slide(percent);
rightSB.isShowingHint = true;
}
if (callback != null) {
float[] result = getCurrentRange();
callback.onRangeChanged(this, result[0], result[1], true);
}
invalidate();
//Intercept parent TouchEvent
if (getParent() != null) {
getParent().requestDisallowInterceptTouchEvent(true);
}
break;
case MotionEvent.ACTION_CANCEL:
if (mSeekBarMode == 2) {
rightSB.isShowingHint = false;
}
leftSB.isShowingHint = false;
if (callback != null) {
float[] result = getCurrentRange();
callback.onRangeChanged(this, result[0], result[1], false);
}
//Intercept parent TouchEvent
if (getParent() != null) {
getParent().requestDisallowInterceptTouchEvent(true);
}
break;
case MotionEvent.ACTION_UP:
if (mSeekBarMode == 2) {
rightSB.isShowingHint = false;
}
leftSB.isShowingHint = false;
currTouch.materialRestore();
if (callback != null) {
float[] result = getCurrentRange();
callback.onRangeChanged(this, result[0], result[1], false);
}
//Intercept parent TouchEvent
if (getParent() != null) {
getParent().requestDisallowInterceptTouchEvent(true);
}
break;
}
return super.onTouchEvent(event);
}
@Override
public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.minValue = minValue - offsetValue;
ss.maxValue = maxValue - offsetValue;
ss.reserveValue = reserveValue;
ss.cellsCount = cellsCount;
float[] results = getCurrentRange();
ss.currSelectedMin = results[0];
ss.currSelectedMax = results[1];
return ss;
}
@Override
public void onRestoreInstanceState(Parcelable state) {
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
float min = ss.minValue;
float max = ss.maxValue;
float reserve = ss.reserveValue;
int cells = ss.cellsCount;
setRules(min, max, reserve, cells);
float currSelectedMin = ss.currSelectedMin;
float currSelectedMax = ss.currSelectedMax;
setValue(currSelectedMin, currSelectedMax);
}
private class SavedState extends BaseSavedState {
private float minValue;
private float maxValue;
private float reserveValue;
private int cellsCount;
private float currSelectedMin;
private float currSelectedMax;
SavedState(Parcelable superState) {
super(superState);
}
private SavedState(Parcel in) {
super(in);
minValue = in.readFloat();
maxValue = in.readFloat();
reserveValue = in.readFloat();
cellsCount = in.readInt();
currSelectedMin = in.readFloat();
currSelectedMax = in.readFloat();
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeFloat(minValue);
out.writeFloat(maxValue);
out.writeFloat(reserveValue);
out.writeInt(cellsCount);
out.writeFloat(currSelectedMin);
out.writeFloat(currSelectedMax);
}
}
/**
* 根据手机的分辨率从 dp 的单位 转成为 px(像素)
*/
private int dp2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/**
* Compare the size of two floating point numbers
*
* @param a
* @param b
* @return 1 is a > b
* -1 is a < b
* 0 is a == b
*/
private int compareFloat(float a, float b) {
int ta = Math.round(a * 1000);
int tb = Math.round(b * 1000);
if (ta > tb) {
return 1;
} else if (ta < tb) {
return -1;
} else {
return 0;
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305
- 306
- 307
- 308
- 309
- 310
- 311
- 312
- 313
- 314
- 315
- 316
- 317
- 318
- 319
- 320
- 321
- 322
- 323
- 324
- 325
- 326
- 327
- 328
- 329
- 330
- 331
- 332
- 333
- 334
- 335
- 336
- 337
- 338
- 339
- 340
- 341
- 342
- 343
- 344
- 345
- 346
- 347
- 348
- 349
- 350
- 351
- 352
- 353
- 354
- 355
- 356
- 357
- 358
- 359
- 360
- 361
- 362
- 363
- 364
- 365
- 366
- 367
- 368
- 369
- 370
- 371
- 372
- 373
- 374
- 375
- 376
- 377
- 378
- 379
- 380
- 381
- 382
- 383
- 384
- 385
- 386
- 387
- 388
- 389
- 390
- 391
- 392
- 393
- 394
- 395
- 396
- 397
- 398
- 399
- 400
- 401
- 402
- 403
- 404
- 405
- 406
- 407
- 408
- 409
- 410
- 411
- 412
- 413
- 414
- 415
- 416
- 417
- 418
- 419
- 420
- 421
- 422
- 423
- 424
- 425
- 426
- 427
- 428
- 429
- 430
- 431
- 432
- 433
- 434
- 435
- 436
- 437
- 438
- 439
- 440
- 441
- 442
- 443
- 444
- 445
- 446
- 447
- 448
- 449
- 450
- 451
- 452
- 453
- 454
- 455
- 456
- 457
- 458
- 459
- 460
- 461
- 462
- 463
- 464
- 465
- 466
- 467
- 468
- 469
- 470
- 471
- 472
- 473
- 474
- 475
- 476
- 477
- 478
- 479
- 480
- 481
- 482
- 483
- 484
- 485
- 486
- 487
- 488
- 489
- 490
- 491
- 492
- 493
- 494
- 495
- 496
- 497
- 498
- 499
- 500
- 501
- 502
- 503
- 504
- 505
- 506
- 507
- 508
- 509
- 510
- 511
- 512
- 513
- 514
- 515
- 516
- 517
- 518
- 519
- 520
- 521
- 522
- 523
- 524
- 525
- 526
- 527
- 528
- 529
- 530
- 531
- 532
- 533
- 534
- 535
- 536
- 537
- 538
- 539
- 540
- 541
- 542
- 543
- 544
- 545
- 546
- 547
- 548
- 549
- 550
- 551
- 552
- 553
- 554
- 555
- 556
- 557
- 558
- 559
- 560
- 561
- 562
- 563
- 564
- 565
- 566
- 567
- 568
- 569
- 570
- 571
- 572
- 573
- 574
- 575
- 576
- 577
- 578
- 579
- 580
- 581
- 582
- 583
- 584
- 585
- 586
- 587
- 588
- 589
- 590
- 591
- 592
- 593
- 594
- 595
- 596
- 597
- 598
- 599
- 600
- 601
- 602
- 603
- 604
- 605
- 606
- 607
- 608
- 609
- 610
- 611
- 612
- 613
- 614
- 615
- 616
- 617
- 618
- 619
- 620
- 621
- 622
- 623
- 624
- 625
- 626
- 627
- 628
- 629
- 630
- 631
- 632
- 633
- 634
- 635
- 636
- 637
- 638
- 639
- 640
- 641
- 642
- 643
- 644
- 645
- 646
- 647
- 648
- 649
- 650
- 651
- 652
- 653
- 654
- 655
- 656
- 657
- 658
- 659
- 660
- 661
- 662
- 663
- 664
- 665
- 666
- 667
- 668
- 669
- 670
- 671
- 672
- 673
- 674
- 675
- 676
- 677
- 678
- 679
- 680
- 681
- 682
- 683
- 684
- 685
- 686
- 687
- 688
- 689
- 690
- 691
- 692
- 693
- 694
- 695
- 696
- 697
- 698
- 699
- 700
- 701
- 702
- 703
- 704
- 705
- 706
- 707
- 708
- 709
- 710
- 711
- 712
- 713
- 714
- 715
- 716
- 717
- 718
- 719
- 720
- 721
- 722
- 723
- 724
- 725
- 726
- 727
- 728
- 729
- 730
- 731
- 732
- 733
- 734
- 735
- 736
- 737
- 738
- 739
- 740
- 741
- 742
- 743
- 744
- 745
- 746
- 747
- 748
- 749
- 750
- 751
- 752
- 753
- 754
- 755
- 756
- 757
- 758
- 759
- 760
- 761
- 762
- 763
- 764
- 765
- 766
- 767
- 768
- 769
- 770
- 771
- 772
- 773
- 774
- 775
- 776
- 777
- 778
- 779
- 780
- 781
- 782
- 783
- 784
- 785
- 786
- 787
- 788
- 789
- 790
- 791
- 792
- 793
- 794
- 795
- 796
- 797
- 798
- 799
- 800
- 801
- 802
- 803
- 804
- 805
- 806
- 807
- 808
- 809
- 810
- 811
- 812
- 813
- 814
- 815
- 816
- 817
- 818
- 819
- 820
- 821
- 822
- 823
- 824
- 825
- 826
- 827
- 828
- 829
- 830
- 831
- 832
- 833
- 834
- 835
- 836
- 837
- 838
- 839
- 840
- 841
- 842
- 843
- 844
- 845
- 846
- 847
- 848
- 849
- 850
- 851
- 852
- 853
- 854
- 855
- 856
- 857
- 858
- 859
- 860
- 861
- 862
- 863
- 864
- 865
- 866
- 867
- 868
- 869
- 870
- 871
- 872
- 873
- 874
- 875
- 876
- 877
- 878
- 879
- 880
- 881
- 882
- 883
- 884
- 885
- 886
- 887
- 888
- 889
- 890
- 891
- 892
- 893
- 894
- 895
- 896
- 897
- 898
- 899
- 900
- 901
- 902
- 903
- 904
- 905
- 906
- 907
- 908
- 909
- 910
- 911
- 912
- 913
- 914
- 915
- 916
- 917
- 918
- 919
- 920
- 921
- 922
- 923
- 924
- 925
- 926
- 927
- 928
- 929
- 930
- 931
- 932
- 933
- 934
- 935
- 936
- 937
- 938
- 939
- 940
- 941
- 942
- 943
- 944
- 945
- 946
- 947
- 948
- 949
- 950
- 951
- 952
- 953
- 954
- 955
- 956
- 957
- 958
- 959
- 960
- 961
- 962
- 963
- 964
- 965
- 966
- 967
- 968
- 969
- 970
- 971
- 972
- 973
- 974
- 975
- 976
- 977
- 978
- 979
- 980
- 981
- 982
- 983
- 984
- 985
- 986
- 987
- 988
- 989
- 990
- 991
- 992
- 993
- 994
- 995
- 996
- 997
- 998
- 999
- 1000
- 1001
- 1002
- 1003
- 1004
- 1005
- 1006
- 1007
- 1008
- 1009
- 1010
- 1011
- 1012
- 1013
- 1014
- 1015
- 1016
- 1017
- 1018
- 1019
- 1020
- 1021
- 1022
- 1023
- 1024
- 1025
- 1026
- 1027
- 1028
- 1029
- 1030
- 1031
- 1032
- 1033
- 1034
- 1035
- 1036
- 1037
- 1038
- 1039
取拖动条的最大值代码块:
//从缓存中拿值
float maxValue = SharePreferencesUtils.getFloat(context, "maxValue", 0);
if (0 == maxValue) {
mMax = t.getFloat(R.styleable.RangeSeekBar_max, 100);//最大取值
} else {
mMax = maxValue;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
这边的maxValue 值是从缓存中取出来的,如果在缓存中这个key(maxValue)为空的话,默认值为0,为0的时候从本地的配置文件arrays.xml中拿取默认的最大值(100),该文件放置在values目录下面,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="markArray">
<item>0</item>
<item>10</item>
<item>20</item>
<item>30</item>
<item>50</item>
<item>100</item>
</string-array>
</resources>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
还有一段就是获取刻度的array。
//从缓存中拿值
CharSequence tempArray[] = SharePreferencesUtils.getStringSet(context, "textArray", null);
if (tempArray == null || tempArray.length == 0) {
mTextArray = t.getTextArray(R.styleable.RangeSeekBar_markTextArray);
} else {
mTextArray = tempArray;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
一样的 存储方式,放在SharePreferences内存当中,默认为null,默认获取的就是上面的arrays.xml文件。不为空则在本内存中获取,那么这边可能有人会问,SharePreferences怎么存储和获取数组元素,我这边贴出来一下:
package com.ds.platform.utils;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
import com.ds.platform.bean.Lot;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* 覆盖模式的SharePreference
*/
public class SharePreferencesUtils {
private final static String SP_NAME = "sp_cache";
private static SharedPreferences mPreferences; // SharedPreferences的实例
private static final String TAG = LogUtils.LogName;
private static SharedPreferences getSp(Context context) {
if (mPreferences == null) {
mPreferences = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);//覆盖
}
return mPreferences;
}
/**
* 通过SP获得boolean类型的数据,没有默认为false
*
* @param context : 上下文
* @param key : 存储的key
* @return
*/
public static boolean getBoolean(Context context, String key) {
SharedPreferences sp = getSp(context);
return sp.getBoolean(key, false);
}
/**
* 通过SP获得boolean类型的数据,没有默认为false
*
* @param context : 上下文
* @param key : 存储的key
* @param defValue : 默认值
* @return
*/
public static boolean getBoolean(Context context, String key, boolean defValue) {
SharedPreferences sp = getSp(context);
return sp.getBoolean(key, defValue);
}
/**
* 设置int的缓存数据
*
* @param context
* @param key :缓存对应的key
* @param value :缓存对应的值
*/
public static void setBoolean(Context context, String key, boolean value) {
SharedPreferences sp = getSp(context);
SharedPreferences.Editor edit = sp.edit();// 获取编辑器
edit.putBoolean(key, value);
edit.commit();
}
/**
* 缓存float
*
* @param context
* @param key
* @param defValue
* @return
*/
public static void setFloat(Context context, String key, float defValue) {
SharedPreferences sp = getSp(context);
SharedPreferences.Editor edit = sp.edit();// 获取编辑器
edit.putFloat(key, defValue);
edit.commit();
}
/**
* 获取int型数据
* @param context
* @param key
* @param defValue
* @return
*/
public static int getInt(Context context, String key, int defValue) {
SharedPreferences sp = getSp(context);
return sp.getInt(key, defValue);
}
/**
* 获取string值
* @param context
* @param key
* @param defValue
* @return
*/
public static String getString(Context context, String key, String defValue) {
SharedPreferences sp = getSp(context);
return sp.getString(key, defValue);
}
public static float getFloat(Context context, String key, float defValue) {
SharedPreferences sp = getSp(context);
return sp.getFloat(key, defValue);
}
public static long getLong(Context context, String key, long defValue) {
SharedPreferences sp = getSp(context);
return sp.getLong(key, 0);
}
/**
* 储存数组
*/
public static void setArrayData(Context context, String key, CharSequence text[]) {
if (text == null || text.length == 0) {
return;
}
SharedPreferences sp = getSp(context);
SharedPreferences.Editor edit = sp.edit();// 获取编辑器
Set set = new HashSet();
for (int i = 0; i < text.length; i++) {
set.add(text[i]);
}
edit.putStringSet(key, set);
edit.commit();
}
/**
* 获取数组
*/
public static CharSequence[] getStringSet(Context context, String key, Set<String> defValue) {
CharSequence sequence[] = new CharSequence[6];
SharedPreferences sp = getSp(context);
Set set = sp.getStringSet(key, defValue);
if (set != null && set.size() > 0) {
Iterator<Object> it = set.iterator();
for (int i = 0; i < set.size(); i++) {
sequence[i] = (CharSequence) it.next();
}
Arrays.sort(sequence);
}
return sequence;
}
/**
* 保存list数据
*/
public static void setArrayList(Context context, String key, ArrayList<Lot> list) {
if (list == null || list.size() == 0) {
return;
}
Log.d(TAG, list.size() + "");
SharedPreferences sp = getSp(context);
SharedPreferences.Editor edit = sp.edit();// 获取编辑器
int size = list.size();
setInt(context, "listSize", size);//保存list的大小
for (int i = 0; i < list.size(); i++) {
edit.putString(key + i, list.get(i).getId());
edit.putString(key + i + "n", list.get(i).getName());
}
edit.commit();
}
/**
* 获取list数据
*/
public static ArrayList<Lot> getArrayList(Context context, String key) {
ArrayList<Lot> list = new ArrayList<>();
int size = getInt(context, "listSize", 0);
for (int i = 0; i < size; i++) {
Lot lot = new Lot();
lot.setId(getString(context, key + i, null));
lot.setName(getString(context, key + i + "n", null));
list.add(lot);
}
return list;
}
//删除list
public static void deleteList(Context context, String key) {
SharedPreferences sp = getSp(context);
SharedPreferences.Editor edit = sp.edit();// 获取编辑器
int size = getInt(context, "listSize", 0);
for (int i = 0; i < size; i++) {
edit.remove(key + i);
edit.remove(key + i + "n");
edit.commit();
}
deleteData(context, "listSize");//删除列表玩法的缓存数据
}
/**
* 设置int的缓存数据
*
* @param context
* @param key :缓存对应的key
* @param value :缓存对应的值
*/
public static void setInt(Context context, String key, int value) {
SharedPreferences sp = getSp(context);
SharedPreferences.Editor edit = sp.edit();// 获取编辑器
edit.putInt(key, value);
edit.commit();
}
public static void setString(Context context, String key, String value) {
SharedPreferences sp = getSp(context);
SharedPreferences.Editor edit = sp.edit();// 获取编辑器
edit.putString(key, value);
edit.commit();
}
public static void setLong(Context context, String key, long value) {
SharedPreferences sp = getSp(context);
SharedPreferences.Editor edit = sp.edit();// 获取编辑器
edit.putLong(key, value);
edit.commit();
}
public static void setInt(Context context, String key, String value) {
SharedPreferences sp = getSp(context);
SharedPreferences.Editor edit = sp.edit();// 获取编辑器
edit.putString(key, value);
edit.commit();
}
/**
* 删除指定key的value
*
* @param context
* @param key
*/
public static void deleteData(Context context, String key) {
SharedPreferences sp = getSp(context);
SharedPreferences.Editor edit = sp.edit();// 获取编辑器
edit.remove(key);
edit.commit();
}
/**
* 清空缓存中的全部数据
*
* @param context
*/
public static void clearData(Context context) {
SharedPreferences sp = getSp(context);
SharedPreferences.Editor editor = sp.edit();
editor.clear().commit();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
上述是我项目中用到的,需要的可以看一下,另外分享一个小技巧,如果你想知道app中存入在Sp内存中的数据怎么看呢?可以在android studio中去查看,工具导航栏Tools–>Android–>Android Device Monitor ,打开之后点击右侧导航菜单的File Explorer ,找到data–>data–>自己的项目包名–>shared_prefs–>自己定义的sp名字,这边定义的是sp_cache,然后该目录下就存在一个sp_cache.xml的文件,点击右上角的图标 第一个导出电脑就可以查看了。好了,原归正传:
我怎么动态设置数组呢?先看下效果图:
不知你们有没有发现一些细节,每次拖动条上面的刻度文字跟跳转另一个activity输入框的数字是顺序大小一样,还有动态去设置刻度值得时候我没有从0开始,而是大于0的数字开始,我也做了启用停用的开关,停用之后不能使用拖动条功能,这个状态也是保存在SP内存里面的。
接下来看一下拖动条的对话框,我使用fragment做的,这边也一起说一下吧!
代码如下:
package com.ds.platform.dialog;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import com.ds.platform.R;
import com.ds.platform.activity.OrderActivity;
import com.ds.platform.utils.LogUtils;
import com.ds.platform.view.RangeSeekBar;
/**
* @author: Allen.
* @date: 2017/4/14
* @description: 拖动条对话框
*/
public class MyDialogFragment extends android.support.v4.app.DialogFragment {
private RangeSeekBar seekbar1;
private String progressData = "0";//初始第一个数值
private static final String TAG = LogUtils.LogName;
private OrderActivity orderActivity;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.dialog_balance_seekbar, null);
orderActivity = (OrderActivity) getActivity();
initView(view);//初始控件
//去除标题
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
setCancelable(true);
return view;
}
/**
* 获取控件
*
* @param view
*/
private void initView(View view) {
seekbar1 = (RangeSeekBar) view.findViewById(R.id.seekbar1);
seekbar1.setValue(0);//设置默认值
//监听控件去设置列表订单的item金额
seekbar1.setOnRangeChangedListener(new RangeSeekBar.OnRangeChangedListener() {
@Override
public void onRangeChanged(RangeSeekBar view, float min, float max, boolean isFromUser) {
seekbar1.setProgressDescription((int) min + "");
progressData = ((int) min) + "";
orderActivity.setMoney(Integer.parseInt(progressData));
}
});
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
那怎么使用这个fragment呢?首先不用思考的,其父类必须继承FragmentActivity,然后在父类的layout中必须有
<FrameLayout
android:id="@+id/fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
- 1
- 2
- 3
- 4
然后可以通过view来触发这个fragment。
FragmentTransaction tran = getSupportFragmentManager().beginTransaction();
MyDialogFragment dialogFragment = new MyDialogFragment();
dialogFragment.show(tran, "myDialog");
- 1
- 2
- 3
需要注意的是要用V4的getSupportFragmentManager。
MyDialogFragment 的layout中需要使用自己定义的seekbar,如下:
<com.dsn.platform.view.RangeSeekBar
android:id="@+id/seekbar1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="@+id/view1"
app:cellMode="number"
app:lineColorEdge="@color/silery"
app:lineColorSelected="@color/main_top"
app:markTextArray="@array/markArray"
app:seekBarMode="single"
app:textPadding="15dp"
app:textSize="@dimen/text14"
app:textColor="@color/login_text"
app:seekBarResId="@drawable/seekbar_thumb" />
</RelativeLayout>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
该控件上的属性封装在attrs.xml中:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- ******************** 参数解释 ******************** -->
<!--最大值-->
<!--最小值-->
<!--两个按钮的最小间距-->
<!--cells 等于0为普通模式,大于1时切换为刻度模式-->
<!--是否关闭进度提示-->
<!--拖动后的Seekbar颜色-->
<!--默认的Seekbar颜色-->
<!--进度为最小值或最大值时按钮的颜色,默认此属性不调用-->
<!--进度不为最小值或最大值时按钮的颜色,默认此属性不调用-->
<!--刻度文字,不设置的时候默认隐藏-->
<!--按钮的背景资源,不设置的时候默认为圆形按钮-->
<!--进度提示背景资源,必须使用 9 path文件-->
<!--刻度文字与进度条之间的距离-->
<!--刻度文字和进度提示文字的大小-->
<!--进度提示背景的高度,不设置时根据文字尺寸自适应-->
<!--进度提示背景的宽度,不设置时根据文字尺寸自适应-->
<!--进度提示背景和进度条之间的距离-->
<!--进度条的高度-->
<!--按钮的尺寸-->
<!--刻度模式
number 根据刻度的实际所占比例分配位置(markTextArray中必须都为数字)
other 平分当前布局(markTextArray可以是任何字符)
-->
<!--单向、双向模式 single 单向模式,只有一个按钮 range 双向模式,有两个按钮 -->
<!-- ******************** 参数解释 ******************** -->
<declare-styleable name="RangeSeekBar">
<attr name="max" format="float"/>
<attr name="min" format="float"/>
<attr name="reserve" format="float"/>
<attr name="cells" format="integer"/>
<attr name="hideProgressHint" format="boolean"/>
<attr name="lineColorSelected" format="color"/>
<attr name="lineColorEdge" format="color"/>
<attr name="thumbPrimaryColor" format="color"/>
<attr name="thumbSecondaryColor" format="color"/>
<attr name="markTextArray" format="reference"/>
<attr name="seekBarResId" format="reference"/>
<!-- must use 9 path !!!-->
<attr name="progressHintResId" format="reference"/>
<attr name="textPadding" format="dimension" />
<attr name="textSize" format="dimension" />
<attr name="textColor" format="color" />
<attr name="hintBGHeight" format="dimension" />
<attr name="hintBGWith" format="dimension" />
<attr name="hintBGPadding" format="dimension" />
<attr name="seekBarHeight" format="dimension"/>
<attr name="thumbSize" format="dimension"/>
<attr name="cellMode" format="enum">
<enum name="number" value="0"/>
<enum name="other" value="1"/>
</attr>
<attr name="seekBarMode" format="enum">
<enum name="single" value="1"/>
<enum name="range" value="2"/>
</attr>
</declare-styleable>
</resources>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
这边要注意progressHintResId属性,设置刻度提示背景必须使用.9的图片。
另一个跳转的activity页面我就不贴代码了,逻辑很简单,把输入的数字封装成数组,存入SP中,然后你每次弹出拖动条对话框,它都会去判断缓存中是否有值。
好了,今天先分享这个,感谢!