示例
功能描述
通过输入的list节点表示标尺刻度,不规定每一个相同,当长度相同,取得的值只能是节点上的值,没有中间值。支持左滑右滑,滑动有动画,并且划过一般自动滑到节点,未满一半返回原节点。
代码
public class RulerView extends View {
/**屏幕宽度*/
private int screenWidth;
/**控件高度*/
private int viewHeight;
/**view宽度*/
private int viewWidth;
/**m每一小格的长度*/
private int oneItemValue;
/**端点节点*/
private List<String> list =new ArrayList<>();
/**滑动监听器*/
private OnRulerChangeListener rulerListener;
/**滚动计算类*/
private Scroller scroller;
/**手势监听*/
private GestureDetector gestureDetector;
/**偏移量*/
private int offset;
/**绘制的开始位置*/
private int location;
/**显示哪个list值*/
private int distanceInteger;
/**游标颜色*/
private int cursorColor;
/**刻度颜色*/
private int scaleColor;
/**刻度字体颜色*/
private int scaleTextColor;
/**刻度字体大小*/
private int scaleTextSize;
/**手指抬起时的偏移量*/
private int upOffset;
/**是否标尺往回走*/
private boolean isBack;
/**字体所处高度比例*/
private float scaleTextHeight;
/**游标长度比例*/
private float cursorHeight;
public void setList(List<String> list) {
this.list = list;
invalidate();
}
public void setRulerListener(OnRulerChangeListener rulerListener) {
this.rulerListener = rulerListener;
}
public RulerView(Context context, AttributeSet attrs) {
super(context, attrs);
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(dm);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RulerView);
cursorColor = typedArray.getColor(R.styleable.RulerView_cursor_color, Color.rgb(255,0,0));
scaleColor = typedArray.getColor(R.styleable.RulerView_scale_color,Color.argb(255,102,102,102));
scaleTextColor = typedArray.getColor(R.styleable.RulerView_scale_text_color,Color.argb(255,102,102,102));
scaleTextSize = typedArray.getDimensionPixelOffset(R.styleable.RulerView_scale_text_size,36);
scaleTextHeight = typedArray.getFloat(R.styleable.RulerView_scale_text_height,(float)0.25);
cursorHeight = typedArray.getFloat(R.styleable.RulerView_cursor_height,(float) 0);
screenWidth = dm.widthPixels;
oneItemValue = screenWidth/20;
//滚动计算器
scroller = new Scroller(context);
//一定要加,不然只会收到onDown,onShowPress,onLongPress3个事件
setClickable(true);
//手势解析
gestureDetector = new GestureDetector(context, gestureListener);
//是否允许长点击
gestureDetector.setIsLongpressEnabled(false);
location=screenWidth/2;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
viewHeight = MeasureSpec.getSize(heightMeasureSpec);
if(list.size() == 0){
list.add("0");
}
viewWidth=oneItemValue*(list.size()-1)*5;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
viewWidth=oneItemValue*(list.size()-1)*5;
drawBottomLine(canvas);
drawScale(canvas);
drawCursor(canvas);
}
/**绘制刻度*/
private void drawScale(Canvas canvas) {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStrokeWidth(3);
paint.setColor(scaleColor);
Paint paintText = new Paint(Paint.ANTI_ALIAS_FLAG);
paintText.setTextSize(scaleTextSize);
paintText.setColor(scaleTextColor);
for(int i=0;i <= (list.size()-1)*5;i++){
int currentLocation=location+i*oneItemValue;
if(i % 5 == 0){
String drawStr;
drawStr = list.get(i/5);
Rect bounds = new Rect();
paintText.getTextBounds(drawStr, 0, drawStr.length(), bounds);
canvas.drawText(drawStr, currentLocation - bounds.width() / 2, viewHeight-viewHeight*scaleTextHeight, paintText);
canvas.drawLine(currentLocation, viewHeight-viewHeight/5, currentLocation, viewHeight, paint);
}else{
canvas.drawLine(currentLocation, viewHeight-viewHeight/8, currentLocation, viewHeight, paint);
}
}
}
/**绘制游标*/
private void drawCursor(Canvas canvas) {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStrokeWidth(3);
paint.setColor(cursorColor);
if(scroller.computeScrollOffset()){
canvas.drawLine(screenWidth/2+scroller.getCurrX(), viewHeight*cursorHeight, screenWidth/2+scroller.getCurrX(), viewHeight, paint);
}else{
canvas.drawLine(screenWidth/2+offset, viewHeight*cursorHeight, screenWidth/2+offset, viewHeight, paint);
}
}
/**绘制底部横线*/
private void drawBottomLine(Canvas canvas) {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStrokeWidth(3);
paint.setColor(Color.rgb(102,102,102));
if(scroller.computeScrollOffset()){
canvas.drawLine(scroller.getCurrX(),viewHeight,screenWidth+scroller.getCurrX(), viewHeight, paint);
}else{
canvas.drawLine(offset, viewHeight, screenWidth+offset, viewHeight, paint);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
gestureDetector.onTouchEvent(event);
if(event.getAction() == MotionEvent.ACTION_UP){
changeValue();
upOffset = offset;
offset = distanceInteger *5*oneItemValue;
if(isBack){
scroller.startScroll(upOffset,0,-(upOffset-offset),0,1000);
}else{
scroller.startScroll(upOffset,0,(offset-upOffset),0,1000);
}
invalidate();
}
return super.onTouchEvent(event);
}
/**改变textView*/
private void changeValue(){
distanceInteger= offset/(oneItemValue*5);
int distanceRemainder = offset % (oneItemValue*5);
if(distanceRemainder >=oneItemValue*5/2){
distanceInteger=distanceInteger+1;
isBack=false;
}else{
isBack=true;
}
if(rulerListener != null){
if(distanceInteger >= list.size()){
distanceInteger = list.size() -1;
}
rulerListener.setValue(Integer.valueOf(list.get(distanceInteger)));
}
}
private GestureDetector.SimpleOnGestureListener gestureListener = new GestureDetector.SimpleOnGestureListener(){
/**
* @param e1 滑动事件的起点(也就是说onDown()的时候)
* @param e2 当前滑动位置点(手指的位置)
* @param distanceX 上次滑动(调用onScroll)到这次滑动的X轴的距离px
* @param distanceY 上次滑动(调用onScroll)到这次滑动的Y轴的距离px
*/
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if(offset >= viewWidth && distanceX >= 0){
distanceX =0;
offset=viewWidth;
}else if(offset <= 0 && distanceX <= 0){
distanceX = 0;
offset =0;
}
scroller.forceFinished(true);
offset=offset+(int)distanceX;
scrollTo(offset,0);
return super.onScroll(e1, e2, distanceX, distanceY);
}
/***
* @param e1 拖动动事件的起点(也就是说onDown()的时候)
* @param e2 onFling()调用时,手指的位置
* @param velocityX X轴上每秒滑动像素值
* @param velocityY Y轴上每秒滑动像素值
* 当拖动速率velocityX或velocityY超过ViewConfiguration.getMinimumFlingVelocity()最小拖动速率时,才会调用onFling(),
* 也就是如果只拖动一点,或是慢慢的拖动,是不会触发该方法
*/
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
scroller.fling(offset, 0, (int) (-velocityX / 1.5), 0, 0, viewWidth, 0, 0);
return super.onFling(e1, e2, velocityX, velocityY);
}
};
@Override
public void computeScroll() {
super.computeScroll();
if(scroller.computeScrollOffset()){
scrollTo(scroller.getCurrX(),0);
invalidate();
}else{
scrollTo(offset,0);
}
}
}
public interface OnRulerChangeListener {
/**设置值*/
void setValue(int value);
}
<resources>
<declare-styleable name="RulerView">
<!--游标的颜色-->
<attr name="cursor_color" format="color"></attr>
<!--刻度颜色-->
<attr name="scale_color" format="color"></attr>
<!--刻度字体颜色-->
<attr name="scale_text_color" format="color"></attr>
<!--刻度字体大小-->
<attr name="scale_text_size" format="dimension"></attr>
<!--字体所处高度-->
<attr name="scale_text_height" format="float"></attr>
<!--游标长度比例-->
<attr name="cursor_height" format="float"></attr>
</declare-styleable>
</resources>
使用
<com.example.RulerView
android:id="@+id/rulerview"
android:layout_width="match_parent"
android:layout_height="70dp"
android:layout_marginTop="10dp"
app:cursor_color="#ff0000"
app:scale_color="#333333"
app:scale_text_color="#333333"
app:scale_text_size="20sp" />
public class MainActivity extends AppCompatActivity implements OnRulerChangeListener {
TextView textView;
RulerView rulerView;
int num;
private int currLocation = 500;
private List<String> list=new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
list.add(0,"500");
list.add(1,"1000");
list.add(2,"1400");
rulerView = (RulerView) findViewById(R.id.rulerview);
rulerView.setRulerListener(this);
rulerView.setList(list);
textView = (TextView) findViewById(R.id.tvValue);
textView.setText(currLocation + "");
}
@Override
public void setValue(int value) {
textView.setText(value+"");
}
}