android 横向刻度选择器,自定义 View 不难:带刻度线的 SeekBar(垂直方向)

86189defda4a

1e97da0737325a6483ccfebbe0ed9c36da93a5137961c-1j0DuG_fw658.png

需求

实现垂直摆放

根据容器大小均匀等分刻度

实现长按监听

思路

将原本水平的 SeekBar 垂直摆放

添加长按接口

根据等分的份数计算每份的长度

使用 Paint 逐个画线

实现

![

86189defda4a

Screenshot_2018-06-04-16-42-04.png

86189defda4a

Screenshot_2018-06-04-16-42-16.png

因为有份数是变动的,我们需要自定义属性

自定义 View

1. 自定义属性

我们将份数定义为 tick_mark_count ,整形

2.支持长按的 VerticalSeekBar

原生的 SeekBar 有坑,即使调用 setOnLongClickListener 也无效,可以自己动手实验一下。So,我们需要自己定义长按接口

package com.feng.launcher.view;

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Rect;

import android.graphics.drawable.Drawable;

import android.os.Handler;

import android.os.Message;

import android.util.AttributeSet;

import android.view.MotionEvent;

import android.widget.SeekBar;

/**

* Created by Administrator on 2018/5/28.

*/

// 支持长按事件垂直摆放的 SeekBar

// VerticalSeekBar have longclick behavior

public class VerticalSeekBar extends SeekBar {

private Drawable mThumb;

private SeekBar.OnSeekBarChangeListener mOnSeekBarChangeListener;

private LongClickListener longClickListener;

private long downTime;

private boolean hasLongTouch = false;//是否已经执行长按操作

private boolean possibleLongTouch = true;//可能是长按

private float lastY;

private float lastX;

private Handler handler = new Handler() {

@Override

public void handleMessage(Message msg) {

if (msg.what == 1 && !hasLongTouch) {

hasLongTouch = true;

if (longClickListener != null) longClickListener.onLongClick();

}

}

};

public VerticalSeekBar(Context context) {

super(context);

}

public VerticalSeekBar(Context context, AttributeSet attrs) {

super(context, attrs);

}

public VerticalSeekBar(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

}

public void setOnSeekBarChangeListener(SeekBar.OnSeekBarChangeListener l) {

mOnSeekBarChangeListener = l;

}

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(h, w, oldh, oldw);

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(heightMeasureSpec, widthMeasureSpec);

setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());

}

protected void onDraw(Canvas c) {

c.rotate(-90);

c.translate(-getHeight(), 0);

super.onDraw(c);

}

void onProgressRefresh(float scale, boolean fromUser) {

Drawable thumb = mThumb;

if (thumb != null) {

setThumbPos(getHeight(), thumb, scale, Integer.MIN_VALUE);

invalidate();

}

if (mOnSeekBarChangeListener != null) {

mOnSeekBarChangeListener.onProgressChanged(this, getProgress(), fromUser);

}

}

private void setThumbPos(int w, Drawable thumb, float scale, int gap) {

int available = w - getPaddingLeft() - getPaddingRight();

int thumbWidth = thumb.getIntrinsicWidth();

int thumbHeight = thumb.getIntrinsicHeight();

int thumbPos = (int) (scale * available + 0.5f);

int topBound, bottomBound;

if (gap == Integer.MIN_VALUE) {

Rect oldBounds = thumb.getBounds();

topBound = oldBounds.top;

bottomBound = oldBounds.bottom;

} else {

topBound = gap;

bottomBound = gap + thumbHeight;

}

thumb.setBounds(thumbPos, topBound, thumbPos + thumbWidth, bottomBound);

}

public void setThumb(Drawable thumb) {

mThumb = thumb;

super.setThumb(thumb);

}

void onStartTrackingTouch() {

if (mOnSeekBarChangeListener != null) {

mOnSeekBarChangeListener.onStartTrackingTouch(this);

}

}

void onStopTrackingTouch() {

if (mOnSeekBarChangeListener != null) {

mOnSeekBarChangeListener.onStopTrackingTouch(this);

}

}

private void attemptClaimDrag() {

if (getParent() != null) {

getParent().requestDisallowInterceptTouchEvent(true);

}

}

@Override

public boolean onTouchEvent(MotionEvent event) {

float y = event.getY();

float x = event.getX();

if (!isEnabled()) {

return false;

}

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN:

setPressed(true);

onStartTrackingTouch();

hasLongTouch = false;// 是否已经执行过长按事件

possibleLongTouch = true;//是否可能为长按模式

lastY = y;

lastX = x;

downTime = System.currentTimeMillis();//记录按下的时间

if (!handler.hasMessages(1)) {//如果消息队列中已有消息 则不在重新发送

handler.sendEmptyMessageDelayed(1, 800);

}

break;

case MotionEvent.ACTION_MOVE:

attemptClaimDrag();

setProgress(getMax() - (int) (getMax() * event.getY() / getHeight()));

onStopTrackingTouch();

//移动时如果x|y滑动了一段距离 则不可能为长按事件 即将 possibleLongTouch置为false

if (lastX != 0 && lastY != 0 && (Math.abs(y - lastY) > 5 || Math.abs(x - lastX) > 5)) {

possibleLongTouch = false;

handler.removeMessages(1);

}

lastY = y;

lastX = x;

break;

case MotionEvent.ACTION_UP:

onStopTrackingTouch();

setPressed(false);

lastX = 0;

lastY = 0;

handler.removeMessages(1);

if (System.currentTimeMillis() - downTime > 800 && possibleLongTouch) {

if (!hasLongTouch) {//如果已经执行过长按操作 则不需要再次执行

hasLongTouch = true;

if (longClickListener != null) {

longClickListener.onLongClick();

}

}

return true;

}

break;

case MotionEvent.ACTION_CANCEL:

onStopTrackingTouch();

setPressed(false);

handler.removeMessages(1);

lastX = 0;

lastY = 0;

break;

}

return true;

}

// 定义长按接口

// define longclick interface

public interface LongClickListener {

void onLongClick();

}

public void setLongClickListener(LongClickListener longClickListener) {

this.longClickListener = longClickListener;

}

}

3.带刻度的SeekBar (只支持垂直,如需水平可以修改 onDraw 方法)

TickMarkSeekBar 继承于 VerticalSeekbar,是为了实现垂直的带刻度 SeekBar

/**

* Created by Administrator on 2018/6/4.

* 带刻度尺的 SeekBar

*/

public class TickMarkSeekBar extends VerticalSeekBar {

private int mTickMarkCount;

private int mColor;

public TickMarkSeekBar(Context context) {

super(context);

}

public TickMarkSeekBar(Context context, AttributeSet attrs) {

super(context, attrs);

TypedArray typedArray =context.obtainStyledAttributes(attrs, R.styleable.TickMarkSeekBar);

try {

mTickMarkCount = typedArray.getInt(R.styleable.TickMarkSeekBar_tick_mark_count,12);

mColor = typedArray.getInt(R.styleable.TickMarkSeekBar_tick_mark_color,Color.GRAY);

}finally {

typedArray.recycle();

}

}

public TickMarkSeekBar(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

}

@Override

protected void onDraw(Canvas c) {

super.onDraw(c);

float startX ;

float startY ;

float stopX ;

float stopY ;

Paint linePaint = new Paint(Paint.ANTI_ALIAS_FLAG);

linePaint.setColor(mColor);

float mTickDiliver = getMeasuredHeight() / mTickMarkCount;

// 画刻度线

for (int i = 0; i< mTickMarkCount; i++) {

stopX = getPaddingLeft()+(i*mTickDiliver);

startX = stopX;

c.drawLine(startX,getMeasuredHeight(),stopX,0,linePaint);

}

}

}

4.使用控件

android:id="@+id/flashlight_seekbar"

android:layout_width="124dp"

android:layout_height="382dp"

android:maxHeight="200dp"

android:progressDrawable="@drawable/seekbar"

android:thumb="@null"

app:tick_mark_count="5"

android:thumbOffset="0dp"

/>

如有错误,欢迎指正

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值