如何在Android中创建循环seekbar

如何在Android中创建循环seekbar,android,android-seekbar,Android,Android Seekbar,有人能指导我在android中制作圆形搜索栏吗??是否有任何例子可以使搜索栏在形状上呈圆形而不是与图像呈线性,有人尝试过吗 参考:带有图像的自定义圆形搜索栏 public class ClockSlider extends View implements DialModel.Listener { /* Display modes */ public static final int CLOCK_SLIDER = 1; public static

有人能指导我在android中制作圆形搜索栏吗??是否有任何例子可以使搜索栏在形状上呈圆形而不是与图像呈线性,有人尝试过吗

参考:

带有图像的自定义圆形搜索栏

  public class ClockSlider extends View implements DialModel.Listener {
        /* Display modes */
        public static final int CLOCK_SLIDER = 1;
        public static final int VOLUME_SLIDER = 2;
        public static final int VIBRATE_PICKER = 3;

        public static final boolean ENABLE_VIBRATE = false;
        private static final int INSETS = 6;
        private static final int MINUTES_PER_HALF_DAY = 100;

        private int width;
        private int height;
        private int centerX;
        private int centerY;
        private int diameter;
        private RectF innerCircle;
        private int displayMode = CLOCK_SLIDER;

        private Calendar start = new GregorianCalendar();
        private int startAngle = 90;
        private Calendar end = new GregorianCalendar();

        /** minutes to shush. */
        private int minutes = 0;

        private Bitmap bgBitmap;
        private Bitmap fgBitmap;
        private Path clipPath = new Path();

        private DialModel model;
        private float luftRotation = 0.0f;
        private int totalNicks = 100;
        private int currentNick = 0;

        public ClockSlider(Context context, AttributeSet attrs) {
            super(context, attrs);

            bgBitmap = BitmapFactory.decodeResource(context.getResources(),R.drawable.black_circle);
            fgBitmap = BitmapFactory.decodeResource(context.getResources(),R.drawable.blue_circle);
            setModel(new DialModel());
        }

        public final void setModel(DialModel model) {
            if (this.model != null) {
                this.model.removeListener(this);
            }
            this.model = model;
            this.model.addListener(this);

            invalidate();
        }

        public final DialModel getModel() {
            return model;
        }



        public Date getStart() {
            return start.getTime();
        }



        public int getMinutes() {
            return minutes;
        }

        public void setMinutes(int minutes) {
            if (minutes == this.minutes) {
                return; // avoid unnecessary repaints
            }
            this.minutes = minutes;
            end.setTimeInMillis(start.getTimeInMillis() + (this.minutes * 60 * 1000L));
            postInvalidate();
        }

    //  public final float getRotationInDegrees() {
    //      return (360.0f / totalNicks) * currentNick;
    //  }

        public Date getEnd() {
            return end.getTime();
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            if (getWidth() != width || getHeight() != height) {
                width = bgBitmap.getWidth();
                height = bgBitmap.getHeight();
    //          width = getWidth();
    //          height = getHeight();
                centerX = width / 2;
                centerY = height / 2;

                diameter = Math.min(width, height) - (2 * INSETS);
                int thickness = diameter / 15;

                int left = (width - diameter) / 2;
                int top = (height - diameter) / 2;
                int bottom = top + diameter;
                int right = left + diameter;
    //          outerCircle = new RectF(left, top, right, bottom);
                int innerDiameter = diameter - thickness * 2;
    //          innerCircle = new RectF(left + thickness, top + thickness, left
    //           + thickness + innerDiameter, top + thickness + innerDiameter);

                innerCircle = new RectF(0, 0,width,height);
                canvas.drawBitmap(bgBitmap, null, innerCircle, null);
            }

            if (displayMode == CLOCK_SLIDER) {
                drawClock(canvas);
            } else {
                throw new AssertionError();
            }
        }
        /**
         * Draw a circle and an arc of the selected duration from start thru end.
         */
        private void drawClock(Canvas canvas) {
            int sweepDegrees = (minutes / 2) - 1;

            canvas.drawBitmap(bgBitmap, null, innerCircle, null);
            // the colored "filled" part of the circle
            drawArc(canvas, startAngle, sweepDegrees);

        }

        @Override
        public void onDialPositionChanged(DialModel sender, int nicksChanged) {
            luftRotation = (float) (Math.random() * 1.0f - 0.5f);
            invalidate();
        }

        private void drawArc(Canvas canvas, int startAngle, int sweepDegrees) {
            if (sweepDegrees <= 0) {
                return;
            }
            clipPath.reset();
            clipPath.moveTo(innerCircle.centerX(), innerCircle.centerY());
            clipPath.arcTo(innerCircle, startAngle + sweepDegrees, -sweepDegrees);
    //      clipPath.lineTo(getWidth() / 2, getHeight() / 2);
            canvas.clipPath(clipPath);

            canvas.drawBitmap(fgBitmap, null, innerCircle, null);

            invalidate();
        }

        /**
         * Accept a touches near the circle's edge, translate it to an angle, and
         * update the sweep angle.
         */
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            int touchX = (int) event.getX();
            int touchY = (int) event.getY();
            int newDisplayMode = displayMode;

            if (event.getAction() == MotionEvent.ACTION_UP) {
                newDisplayMode = CLOCK_SLIDER;
            }

            int distanceFromCenterX = centerX - touchX;
            int distanceFromCenterY = centerY - touchY;
            int distanceFromCenterSquared = distanceFromCenterX * distanceFromCenterX + distanceFromCenterY * distanceFromCenterY;
            float maxSlider = (diameter * 1.3f) / 2;
            float maxUpDown = (diameter * 0.8f) / 2;

            /*
             * Convert the angle into a sweep angle. The sweep angle is a positive
             * angle between the start angle and the touched angle.
             */
    //       if (distanceFromCenterSquared < (maxSlider * maxSlider)) {
            float x1 = bgBitmap.getWidth(), x2 = bgBitmap.getHeight(), y1 = bgBitmap
                    .getWidth(), y2 = bgBitmap.getHeight();
            if ((touchX <= x1 && touchX <= x2)  && (touchY <= y1 && touchY <= y2)) {
                int angle = pointToAngle(touchX, touchY);
                angle = 360 + angle - startAngle;
                int angleX2 = angle * 2;
                angleX2 = roundToNearest15(angleX2);
                if (angleX2 > 720) {
                    angleX2 = angleX2 - 720; // avoid mod because we prefer 720 over
                }
                if (angle <= 364) {
                    angleX2 = 0;
                }
    //          if (angleX2 > 720 || angleX2 < 400) {
    //              return false;
    //          }
                setMinutes(angleX2);
                model.rotate(Integer.valueOf("" + Math.round((angleX2 / 5.4))));
                return true;
            } else {

                return false;
            }
        }


        public int getProgress(){
            return minutes;
        }
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int width = MeasureSpec.getSize(widthMeasureSpec);
            int height = MeasureSpec.getSize(heightMeasureSpec);

            // Don't use the full screen width on tablets!
            DisplayMetrics metrics = new DisplayMetrics();
            WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
            windowManager.getDefaultDisplay().getMetrics(metrics);
            float maxWidthInches = 2.3f;

            width = Math.min(width, (int) (maxWidthInches * metrics.densityDpi));
            height = Math.min(height, (int) (width * 0.7f));

            setMeasuredDimension(width, height);
        }

        /**
         * Returns the number of degrees (0-359) for the given point, such that 3pm
         * is 0 and 9pm is 180.
         */
        private int pointToAngle(int x, int y) {

            if (x >= centerX && y < centerY) {
                double opp = x - centerX;
                double adj = centerY - y;
                return 270 + (int) Math.toDegrees(Math.atan(opp / adj));
            } else if (x > centerX && y >= centerY) {
                double opp = y - centerY;
                double adj = x - centerX;
                return (int) Math.toDegrees(Math.atan(opp / adj));
            } else if (x <= centerX && y > centerY) {
                double opp = centerX - x;
                double adj = y - centerY;
                return 90 + (int) Math.toDegrees(Math.atan(opp / adj));
            } else if (x < centerX && y <= centerY) {
                double opp = centerY - y;
                double adj = centerX - x;
                return 180 + (int) Math.toDegrees(Math.atan(opp / adj));
            }

            throw new IllegalArgumentException();
        }

        /**
         * Rounds the angle to the nearest 7.5 degrees, which equals 15 minutes on a
         * clock. Not strictly necessary, but it discourages fat-fingered users from
         * being frustrated when trying to select a fine-grained period.
         */
        private int roundToNearest15(int angleX2) {
            return ((angleX2 + 8) / 15) * 15;
        }

    }
公共类ClockSlider扩展视图实现DialModel.Listener{
/*显示模式*/
公共静态最终整数时钟_滑块=1;
公共静态最终整数卷_滑块=2;
公共静态最终int振动_选择器=3;
公共静态最终布尔值ENABLE_VIMBER=false;
专用静态最终整数插入=6;
私人静态最终整数分钟/半天=100;
私有整数宽度;
私人内部高度;
私人int centerX;
私人国际中心;
私有内径;
私有RectF内循环;
专用int显示模式=时钟滑块;
专用日历开始=新的公历日历();
私人int startAngle=90;
私有日历结束=新的公历日历();
/**还有几分钟就要闭嘴了*/
私人整数分钟=0;
私有位图;
私有位图;
私有路径clipPath=新路径();
私有拨号模式;
私人浮动德国航空旋转=0.0f;
私有整数totalNicks=100;
private int currentNick=0;
公共时钟滑块(上下文、属性集属性){
超级(上下文,attrs);
bgBitmap=BitmapFactory.decodeResource(context.getResources(),R.drawable.black_圆圈);
fgBitmap=BitmapFactory.decodeResource(context.getResources(),R.drawable.blue_圆圈);
setModel(新的DialModel());
}
公共最终作废集合模型(DialModel模型){
如果(this.model!=null){
this.model.removeListener(this);
}
this.model=模型;
this.model.addListener(this);
使无效();
}
公共最终拨号模型getModel(){
收益模型;
}
公共日期getStart(){
返回start.getTime();
}
公共int getMinutes(){
返回分钟数;
}
公共无效设置分钟数(整数分钟){
如果(分钟==此.minutes){
return;//避免不必要的重新绘制
}
这个。分钟=分钟;
end.setTimeInMillis(start.getTimeInMillis()+(this.minutes*60*1000L));
后验证();
}
//公共最终浮点GetRotationDegrees(){
//返回(360.0华氏度/总刻痕)*当前刻痕;
//  }
公共日期getEnd(){
返回end.getTime();
}
@凌驾
受保护的void onDraw(画布){
super.onDraw(帆布);
如果(getWidth()!=宽度| | getHeight()!=高度){
width=bgBitmap.getWidth();
height=bgp位图.getHeight();
//宽度=getWidth();
//高度=getHeight();
centerX=宽度/2;
中心Y=高度/2;
直径=数学最小值(宽度、高度)-(2*插图);
内部厚度=直径/15;
int left=(宽度-直径)/2;
int top=(高度-直径)/2;
内底=顶+直径;
int right=左+直径;
//outerCircle=新的RectF(左、上、右、下);
内径=直径-厚度*2;
//内圆=新矩形(左+厚度,顶部+厚度,左
//+厚度+内径,顶部+厚度+内径);
内圆=新的矩形(0,0,宽度,高度);
drawBitmap(bgBitmap,null,innerCircle,null);
}
if(显示模式==时钟滑块){
挂钟(帆布);
}否则{
抛出新的断言错误();
}
}
/**
*从起点到终点绘制所选持续时间的圆和圆弧。
*/
专用void挂钟(帆布){
整数度=(分钟/2)-1;
drawBitmap(bgBitmap,null,innerCircle,null);
//圆圈的彩色“填充”部分
drawArc(画布、星形缠结、扫掠度);
}
@凌驾
公共无效onDialPositionChanged(拨号模式发送器,int nicksChanged){
德国旋转=(浮动)(数学随机()*1.0f-0.5f);
使无效();
}
私有void drawArc(画布、整型startAngle、整型sweepDegrees){
如果(扫掠角度=中心X和y<中心y){
双opp=x-中心x;
双调整=中心y-y;
返回270+(int)Math.toDegrees(Math.atan(opp/adj));
}如果(x>centerX&&y>=centerY),则为else{
双opp=y-中心;
双调整=x-中心x;
返回(int)Math.toDegrees(Math.atan(opp/adj));
}else if(x centerY){
双opp=中心x-x;
双调整=y-中心;
返回90+(int)Math.toDegrees(Math.atan(opp/adj));

}else if(x

我建立了自己的图书馆。CircularArrangeSlider

演示应用程序(Playstore):

检查一下,它可能适合你的需要


是否可以更改为thumb drawable?虽然这是一个很好的答案,但您需要发布一个关于如何使用它的示例。将来可能会丢失一个链接。这是一个与AndroidX不兼容的伟大的库机器人。是的,这是一个伟大的库,但我需要使用两个拇指,如范围搜索栏。我检查了许多示例,但没有