Andorid自定义拖动弧形进度条

本文介绍如何在Android中实现一个可拖动的弧形进度条,包括初始化参数、尺寸获取、OnTouchEvent处理,以及适配屏幕尺寸的方法。通过自定义View,实现了在触摸事件中动态更新进度的效果,提供了类似拨码盘的功能。
摘要由CSDN通过智能技术生成

在android自定义控件中,我们使用进度显示,为了好看,一般都不会用系统自带的。原因大家都懂的。而现在各种自定义进度条显示也是层出不穷,在实际开发中遇到的情况是需要带拖动效果的弧形进度条。下面我们先看看这个效果图:这张是加了圆圈内进度显示这张是没加拖动圆圈进度显示
开始自定义之前,我们就要把要用到的东西先定义出来,初始化

//进度边框画笔
     private Paint bgpaint;
     //进度底色画笔
    private Paint colorpaint;
    //文本画笔
    private Paint txtpaint;
    //进度颜色画笔
    private Paint propaint;
    //控件中心位置坐标
    private int cx, cy;
    //控件宽高
    private int width, height;
    //弧形体宽高
    private int whsize;
    //判断是否按下
    private boolean isdown;
    //分配圆弧数的比例
    private float angle = 180 / 13;

    private Paint cicpaint;
    //当前点
    private int currentdit;

在构造方法中初始化相关参数

 private void init()
    {
        bgpaint = new Paint();
        colorpaint = new Paint();
        txtpaint = new Paint();
        propaint = new Paint();
        cicpaint = new Paint();
        cicwpaint = new Paint();
        //抗锯齿
        bgpaint.setAntiAlias(true);
        //设置颜色
        bgpaint.setColor(Color.GREEN);
        //设置画笔风格 空心
        bgpaint.setStyle(Paint.Style.STROKE);
        //画笔宽度
        bgpaint.setStrokeWidth(35);
        //设置画笔尾部圆滑
        bgpaint.setStrokeCap(Paint.Cap.ROUND);

        colorpaint.setAntiAlias(true);
        colorpaint.setColor(Color.WHITE);
        colorpaint.setStyle(Paint.Style.STROKE);
        colorpaint.setStrokeWidth(33);
        colorpaint.setStrokeCap(Paint.Cap.ROUND);

        propaint.setAntiAlias(true);
        propaint.setColor(Color.GREEN);
        propaint.setStyle(Paint.Style.STROKE);
        propaint.setStrokeWidth(33);
        propaint.setStrokeCap(Paint.Cap.ROUND);

        txtpaint.setAntiAlias(true);
        txtpaint.setColor(Color.BLACK);
        txtpaint.setStyle(Paint.Style.FILL);
        txtpaint.setStrokeWidth(1);
        txtpaint.setTextSize(30);

        cicpaint.setAntiAlias(true);
        cicpaint.setColor(Color.GREEN);
        cicpaint.setStyle(Paint.Style.FILL);
        cicpaint.setStrokeWidth(1);
        cicpaint.setTextSize(20);

        cicwpaint.setAntiAlias(true);
        cicwpaint.setColor(Color.WHITE);
        cicwpaint.setStyle(Paint.Style.FILL);
        cicwpaint.setStrokeWidth(1);
        cicwpaint.setTextSize(20);
        //保存点的位置
        point.x = (int) Dp2Px(getContext(), 45);
        point.y = (int) (whsize - Dp2Px(getContext(), 45));

    }

将初始化方法,放入构造方法中

 public MyView(Context context)
    {
        super(context);
        init();
    }

    public MyView(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        init();
    }

我们这个自定义控件没有设置自有属性,大家可以自由扩展,好了接下来,就是要获得尺寸。那么有两种方式,一种是在onMeasure()方法中得到控件的宽高。还有就是在onSizeChanged()方法中获得View的高宽。这次我们在onSizeChanged()方法中获得,如果对控件的测量有不熟悉的,可以看看我上一篇blog,android控件测量与布局
onsizechange()方法中怎么获得呢,请看:

 @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh)
    {
        width = w;
        height = h;
        whsize = w > h ? h : w;
        cx = width / 2;
        cy = height / 2;
        super.onSizeChanged(w, h, oldw, oldh);
    }

尺寸得到之后,我们就开始显示进度了。当然通过onDraw()方法。分别画进度背景,线条,等

 @Override
    protected void onDraw(Canvas canvas)
    {
        super.onDraw(canvas);
        drawarc(canvas);
        Log.d("renk", "invar");
        if (isdown)
        {
            drawmap(canvas);
        } else
        {
            drawbit(canvas);
        }
    }

先画,进度背景及边框

private void drawarc(Canvas canvas)
    {
        RectF oval = new RectF(Dp2Px(getContext(), 45),
                Dp2Px(getContext(), 45), whsize - Dp2Px(getContext(), 45),
                whsize - Dp2Px(getContext(), 45));
                //画圆弧
        canvas.drawArc(oval, -180, 180, false, bgpaint);
        canvas.dra
以下是一个简单的自定义View实现K线图的代码示例: ``` public class KLineView extends View { private List<KLineData> mData; // K线数据 private int mWidth, mHeight; // 控件宽度、高度 private int mTopPadding; // 顶部留白 private int mBottomPadding; // 底部留白 private Paint mLinePaint; // K线画笔 private Paint mTextPaint; // 文本画笔 private float mMaxPrice, mMinPrice; // 最高价、最低价 private float mPriceScale; // 价格缩放比例 private float mVolumeScale; // 成交量缩放比例 private int mCandleWidth; // K线宽度 private int mCandleSpace; // K线间隔 public KLineView(Context context) { this(context, null); } public KLineView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public KLineView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); // 初始化画笔 mLinePaint = new Paint(); mLinePaint.setStrokeWidth(2f); mLinePaint.setAntiAlias(true); mLinePaint.setStyle(Paint.Style.STROKE); mTextPaint = new Paint(); mTextPaint.setTextSize(24f); mTextPaint.setAntiAlias(true); mTextPaint.setColor(Color.BLACK); // 初始化K线宽度、间隔 mCandleWidth = dp2px(8); mCandleSpace = dp2px(4); // 初始化留白 mTopPadding = dp2px(20); mBottomPadding = dp2px(20); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); // 获取控件宽度、高度 mWidth = MeasureSpec.getSize(widthMeasureSpec); mHeight = MeasureSpec.getSize(heightMeasureSpec); // 计算价格、成交量缩放比例 mPriceScale = (mHeight - mTopPadding - mBottomPadding) / (mMaxPrice - mMinPrice); mVolumeScale = (mHeight - mTopPadding - mBottomPadding) / getMaxVolume(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 绘制K线图 drawCandles(canvas); // 绘制边框 drawBorder(canvas); // 绘制Y轴标签 drawYLabels(canvas); } /** * 绘制K线图 */ private void drawCandles(Canvas canvas) { if (mData == null || mData.size() == 0) { return; } mLinePaint.setColor(Color.RED); mLinePaint.setStyle(Paint.Style.FILL); float startX = mCandleWidth / 2 + mCandleSpace; // 第一个K线起始X坐标 float startY = 0f; // K线起始Y坐标 float endX, endY; // K线结束X坐标、Y坐标 for (int i = 0; i < mData.size(); i++) { KLineData data = mData.get(i); // 计算K线顶部、底部Y坐标 float highY = mTopPadding + (mMaxPrice - data.getHigh()) * mPriceScale; float lowY = mTopPadding + (mMaxPrice - data.getLow()) * mPriceScale; // 计算K线开盘、收盘Y坐标 float openY = mTopPadding + (mMaxPrice - data.getOpen()) * mPriceScale; float closeY = mTopPadding + (mMaxPrice - data.getClose()) * mPriceScale; // 绘制K线实体 if (data.getOpen() < data.getClose()) { mLinePaint.setColor(Color.RED); } else { mLinePaint.setColor(Color.GREEN); } canvas.drawRect(startX - mCandleWidth / 2, closeY, startX + mCandleWidth / 2, openY, mLinePaint); // 绘制K线上下影线 mLinePaint.setColor(Color.BLACK); canvas.drawLine(startX, highY, startX, openY, mLinePaint); canvas.drawLine(startX, lowY, startX, closeY, mLinePaint); // 更新起始X坐标 startX += mCandleWidth + mCandleSpace; } } /** * 绘制边框 */ private void drawBorder(Canvas canvas) { mLinePaint.setColor(Color.BLACK); mLinePaint.setStyle(Paint.Style.STROKE); canvas.drawRect(0, 0, mWidth, mHeight, mLinePaint); } /** * 绘制Y轴标签 */ private void drawYLabels(Canvas canvas) { float labelHeight = mTextPaint.descent() - mTextPaint.ascent(); // 绘制价格标签 float priceLabelY = mTopPadding - mTextPaint.ascent(); for (float price = mMinPrice; price <= mMaxPrice; price += (mMaxPrice - mMinPrice) / 5) { float priceY = mTopPadding + (mMaxPrice - price) * mPriceScale; canvas.drawText(String.format(Locale.getDefault(), "%.2f", price), 0, priceY + labelHeight / 2, mTextPaint); canvas.drawLine(mCandleWidth / 2, priceY, mWidth, priceY, mLinePaint); } // 绘制成交量标签 float volumeLabelY = mHeight - mBottomPadding - mTextPaint.descent(); float maxVolume = getMaxVolume(); for (int i = 0; i < 5; i++) { float volumeY = volumeLabelY - i * labelHeight * maxVolume / 5; canvas.drawText(String.format(Locale.getDefault(), "%.0f", maxVolume * i / 5), 0, volumeY - labelHeight / 2, mTextPaint); } } /** * 设置K线数据 */ public void setData(List<KLineData> data) { mData = data; calculateMaxAndMinPrice(); requestLayout(); invalidate(); } /** * 计算最高价、最低价 */ private void calculateMaxAndMinPrice() { if (mData == null || mData.size() == 0) { return; } mMaxPrice = mData.get(0).getHigh(); mMinPrice = mData.get(0).getLow(); for (int i = 1; i < mData.size(); i++) { KLineData data = mData.get(i); mMaxPrice = Math.max(mMaxPrice, data.getHigh()); mMinPrice = Math.min(mMinPrice, data.getLow()); } } /** * 获取最大成交量 */ private float getMaxVolume() { float maxVolume = 0f; if (mData != null && mData.size() > 0) { for (KLineData data : mData) { maxVolume = Math.max(maxVolume, data.getVolume()); } } return maxVolume; } /** * dp转px */ private int dp2px(int dp) { return (int) (dp * getContext().getResources().getDisplayMetrics().density + 0.5f); } } ``` 其中,KLineData表示K线数据,包括开盘价、收盘价、最高价、最低价、成交量等属性。可以根据实际需求进行修改。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值