仿ios进度条
2016-05-06 16:54:00 weixin_33937913 阅读数 22

标签(空格分隔): progress windows 进度条 iOS


最近喜欢上了windows上的进度条,蛮有感觉的,决定仿照着自己写一个
先看原图

1025705-9765fdefdc5efb9a.gif
这是windows的

然后看下我弄的

1025705-ae87ff7673ea0e5a.gif
这是我弄的

颜色比例就不要去追求了吧

接下来说下这个是怎么做的

1, 建立了三个渐变图层,分别是灰色,绿色,和白色的三个图层
2, 创建一个位移动画,用来移动白色渐变图层
3, 每次更改进度条的当前值得同时,对绿色渐变层的大小进行更改

这样一个仿照windows的进度条就完成了.下面说下这个有一个缺陷

  • 这个东西我没处理好白色渐变层的移动,现在只不过是白色渐变层在整个区域的移动,如果超出绿色边界,在设置了maskToBounds的情况下使其不显示了而已
    算是一个取巧吧

欢饮大家访问我的博客进行留言,我会第一时间回复的,谢谢

点我有惊喜

代码下载

2016-08-31 22:04:00 weixin_33923762 阅读数 18
/**
 * Created by C058 on 2016/5/25.
 */
public class MyHoriztalProgressBar extends ProgressBar {

    private static final int DEFAULT_REACH_COLOR = 0xff24F569;
    private static final int DEFAULT_UNREACH_COLOR = 0xffC0C0C0;
    private static final int DEFAULT_REACH_HEIGHT = 1;
    private static final int DEFAULT_UNREACH_HEIGHT = 2;
    private static final int DEFAULT_TEXT_COLOR = DEFAULT_REACH_COLOR;
    private static final int DEFAULT_TEXT_SIZE = 12;
    private static final int DEFAULT_TEXT_OFFSET = 5;

    protected int mReachColor = DEFAULT_REACH_COLOR;
    protected int mUnReachColor = DEFAULT_UNREACH_COLOR;
    protected int mReachHeight = dp2px(DEFAULT_REACH_HEIGHT);
    protected int mUnReachHeight = dp2px(DEFAULT_UNREACH_HEIGHT);
    protected int mTextColor = DEFAULT_TEXT_COLOR;
    protected int mTextSize = sp2px(DEFAULT_TEXT_SIZE);
    protected int mTextOffset = dp2px(DEFAULT_TEXT_OFFSET);

    protected Paint mPaint = new Paint();
    private int mRealWidth;

    public MyHoriztalProgressBar(Context context) {
        this(context, null);
    }

    public MyHoriztalProgressBar(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyHoriztalProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.MyHoriztalProgressBar);
        mReachColor = ta.getColor(R.styleable.MyHoriztalProgressBar_progressbar_reach_color, mReachColor);
        mUnReachColor = ta.getColor(R.styleable.MyHoriztalProgressBar_progressbar_unreach_color, mUnReachColor);
        mReachHeight = (int) ta.getDimension(R.styleable.MyHoriztalProgressBar_progressbar_reach_height, mReachHeight);
        mUnReachHeight = (int) ta.getDimension(R.styleable.MyHoriztalProgressBar_progressbar_unreach_height, mUnReachHeight);
        mTextColor = ta.getColor(R.styleable.MyHoriztalProgressBar_progressbar_text_color, mTextColor);
        mTextSize = (int) ta.getDimension(R.styleable.MyHoriztalProgressBar_progressbar_text_size, mTextSize);
        mTextOffset = (int) ta.getDimension(R.styleable.MyHoriztalProgressBar_progressbar_text_offset, mTextOffset);
        ta.recycle();
        mPaint.setTextSize(mTextSize);
    }

    @Override
    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthVal = MeasureSpec.getSize(widthMeasureSpec);
        int heightVal = measureHeight(heightMeasureSpec);

        setMeasuredDimension(widthVal, heightVal);
        mRealWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
    }

    @Override
    protected synchronized void onDraw(Canvas canvas) {
        //draw reachBar
        String text = getProgress() + "%";
        int textWidth = (int) mPaint.measureText(text);
        boolean noNeedUnrechBar = false;

        canvas.save();
        canvas.translate(getPaddingLeft(), getMeasuredHeight() / 2);
        float radio = getProgress() * 1.0f / getMax();
        float progressX = mRealWidth * radio;
        if (progressX + textWidth > mRealWidth) {
            progressX = mRealWidth - textWidth;
            noNeedUnrechBar = true;
        }
        //draw reachbar
        mPaint.setColor(mReachColor);
        mPaint.setStrokeWidth(mReachHeight);
        float endX = progressX - mTextOffset / 2;
        canvas.drawLine(0, 0, endX, 0, mPaint);
        //draw text
        mPaint.setColor(mTextColor);
        float y = -(mPaint.descent() + mPaint.ascent())/2;
        canvas.drawText(text, progressX,y, mPaint);
        //draw unreachbar
        if (!noNeedUnrechBar) {
            mPaint.setColor(mUnReachColor);
            mPaint.setStrokeWidth(mUnReachHeight);
            float startX = progressX + textWidth + mTextOffset / 2;
            canvas.drawLine(startX, 0, mRealWidth, 0, mPaint);
        }
        canvas.restore();
    }

    private int measureHeight(int heightMeasureSpec) {
        int mode = MeasureSpec.getMode(heightMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        int result = 0;
        if (mode == MeasureSpec.EXACTLY||mode == MeasureSpec.UNSPECIFIED) {
            result = height;
        } else if (mode == MeasureSpec.AT_MOST) {
            int textHeight = (int) (mPaint.descent() - mPaint.ascent());
            result = getPaddingTop() + getPaddingBottom() + Math.max(Math.max(mReachHeight, mUnReachHeight), textHeight);
//            {
//                result = Math.min(result, height);
//            }
        }
        return result;
    }

    protected int dp2px(int dp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
    }

    protected int sp2px(int sp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getResources().getDisplayMetrics());
    }
}
/**
 * Created by C058 on 2016/5/26.
 * 模仿ios app store应用下载圆形进图条
 */
public class MyRoundProgressBar extends MyHoriztalProgressBar {

    private static final int DEFAULT_PROGRESS_RADIUS = 30;
    private int mRadius = dp2px(DEFAULT_PROGRESS_RADIUS);
    private int mInRadius;
    private RectF mRectf, mInRectf;

    public MyRoundProgressBar(Context context) {
        this(context, null);
    }

    public MyRoundProgressBar(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyRoundProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.MyRoundProgressBar);
        mRadius = (int) ta.getDimension(R.styleable.MyRoundProgressBar_progressbar_radius, mRadius);
        ta.recycle();

        mReachHeight = mUnReachHeight * 2;
        mPaint.setAntiAlias(true);//抗锯齿
        mPaint.setDither(true); //防抖动模式
        mPaint.setStyle(Paint.Style.STROKE);//画笔风格设置为空心
        mPaint.setStrokeCap(Paint.Cap.ROUND);
    }

    @Override
    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int diameter = mRadius * 2 + getPaddingLeft() + getPaddingRight() + mUnReachHeight * 2; //控件宽度 默认四个padding一致
        int width = resolveSize(diameter, widthMeasureSpec);
        int height = resolveSize(diameter, heightMeasureSpec);
        int realWidth = Math.min(width, height);//当宽高设置不一致,取小的那个
        //外圆的半径
        mRadius = (realWidth - getPaddingLeft() - getPaddingRight() - mUnReachHeight) / 2;
        mRectf = new RectF(0, 0, mRadius * 2, mRadius * 2);
        //内圆的半径
        mInRadius = mRadius - mUnReachHeight;
        mInRectf = new RectF(0, 0, mInRadius * 2, mInRadius * 2);
        setMeasuredDimension(realWidth, realWidth);
    }

    @Override
    protected synchronized void onDraw(Canvas canvas) {

        canvas.save();
        canvas.translate(getPaddingLeft(), getPaddingTop());
        //draw unreachbar
        mPaint.setColor(mUnReachColor);
        mPaint.setStrokeWidth(mUnReachHeight);
        //从圆点开始画圆
//        canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);
        //draw reachbar
        //将画布移动到画内圆的位置
        canvas.translate(mUnReachHeight, mUnReachHeight);
        mPaint.setColor(mReachColor);
        mPaint.setStrokeWidth(mReachHeight);
        float sweepAngle = getProgress() * 1.0f / getMax() * 360;
        canvas.drawArc(mInRectf, -90, sweepAngle, false, mPaint);
//        //draw text
//        String text = getProgress() + "%";
//        int textWidth = (int) mPaint.measureText(text);
//        int textHeight = (int) ((mPaint.descent() + mPaint.ascent()) / 2);
//        mPaint.setColor(mTextColor);
//        canvas.drawText(text, mRadius - textWidth / 2, mRadius - textHeight, mPaint);
        canvas.restore();
    }
}
    <declare-styleable name="MyHoriztalProgressBar">
        <attr name="progressbar_reach_color" format="color" />
        <attr name="progressbar_unreach_color" format="color" />
        <attr name="progressbar_reach_height" format="dimension" />
        <attr name="progressbar_unreach_height" format="dimension" />
        <attr name="progressbar_text_color" format="color" />
        <attr name="progressbar_text_size" format="dimension" />
        <attr name="progressbar_text_offset" format="dimension" />
    </declare-styleable>
    <declare-styleable name="MyRoundProgressBar">
        <attr name="progressbar_radius" format="dimension" />
    </declare-styleable>
    <declare-styleable name="MyHoriztalProgressBar2">
        <attr name="reach_color" format="color" />
        <attr name="unreach_color" format="color" />
        <attr name="progressbar_height" format="dimension" />
    </declare-styleable>
 new Timer().schedule(new TimerTask() {
    int currentIndex = (int) Math.floor(current * 100 / total);
    int sumIndex = 0;

    @Override
    public void run() {
        if (currentIndex > sumIndex) {
            sumIndex = currentIndex;
            LogHelp.i("polyv", "current:" + current + "-------total:" + total + "-------currentIndex:" + currentIndex);
            holder.videoList_progress.setProgress(sumIndex);
        }
    }
}, 200, 200);

 

2016-12-29 16:35:28 qq953655369 阅读数 2403
Tag:

项目介绍:

  • 问题1:在iOS开发中,各种优秀的开源控件总是源源不断的涌出,但是在Android开发中虽然开源的东西也不少,但是能拿来直接用到项目中的控件有几个呀?(可能是我没找到O__O "…)

  • 问题2:项目中经常要求Android和iOS的UI效果一致,然而提示控件现在还真TM没找到跨平台效果一致的,这可咋整?(其实你也可以找你UI设计师去商量……)

  • 问题3:我终于找到了一个提示控件的开源代码工程,可是里面的提示控件和我们的UI给出的样式不一样呀!这可咋办,改源代码吗?(……)

  • 问题4:开源控件有bug怎么办,找谁解决啊?自己读源码,改?(OH MY GOD,好多代码,从哪下手?)

等会,废话有点多了,用这行做下分割,下面开始讲我们的主角:LemonBubble......

LemonBubble,中文名称:柠檬泡泡,现支持:Android、iOS-Objc、iOS-Swift三个平台

版本名称 Github地址
LemonBubble4Android https://github.com/1em0nsOft/LemonBubble4Android
LemonBubble4iOS https://github.com/1em0nsOft/LemonBubble

先来看看我们的Sample运行效果图吧:
LemonBubble4Android

效果图中这只是几个小例子供大家看看哦,其实在LemonBubble中,有一个模型对象,叫LemonBubbleInfo,它里面有若干个属性,你可以通过创建一个LemonBubbleInfo对象,然后修改其属性的方式来自定义任意效果的泡泡控件哦!

那么,怎么将LemonBubble集成到你的项目当中呢?你可以使用Gradle,需要首先在你的Project build.gradle文件中(allprojects ->repositories节点)加入如下代码:

allprojects {
    repositories {
        jcenter()
        // 加入下面这行
        maven { url 'https://jitpack.io' }
    }
}

然后在你的Module(xxx e.g:app) build.gradle中(dependencies节点)加入如下代码:

dependencies {
    // ...  你的其他依赖
    // 然后加入下面这行
    compile 'com.github.1em0nsOft:LemonBubble4Android:1.0.0'
}

最后重新build一下就可以啦。

接下来,我们验证一下我们是否集成成功,随便找一个Activity,在onCreate方法里面我们加上如下一行代码:

LemonBubble.showRight(this, "集成成功!", 2000);

运行一下,可以看到如下界面,说明我们集成成功咯!

图片描述

LemonBubble默认自带了三种泡泡样式,带有一个绿色的对号的成功泡泡,带有一个红色X错号的错误泡泡,带有蓝色无限旋转的等待控件,你可以使用如下三种方式调用他们:

LemonBubble.showRight(this, "成功啦!", 2000);
LemonBubble.showError(this, "出错啦", 2000);
LemonBubble.showRoundProgress(this, "等待中...");

上面三个方法中,showRight和showError可以通过传入的第三个参数来控制泡泡显示的时间,单位ms。当你弹出了一个泡泡控件之后你也可以随时使用LemonBubble.hide()进行关闭当前正在显示的泡泡控件。

如果你想自定义样式的话,你只需要新建一个LemonBubbleInfo对象,然后对其进行修改属性即可,你也可以分别通过

LemonBubble.getRightBubbleInfo()
LemonBubble.getErrorBubbleInfo()
LemonBubble.getRoundProgressBubbleInfo()

三个方法来获取我们预先为您写好的包含正确、错误、等待信息的LemonBubbleInfo对象,然后通过修改其属性的方式来快速自定义自己的泡泡控件,比如,我们现在通过如下代码自定义泡泡信息对象:

// 获取默认的正确信息的泡泡信息对象
LemonBubbleInfo myInfo = LemonBubble.getRightBubbleInfo();
// 设置图标在左侧,标题在右侧
myInfo.setLayoutStyle(LemonBubbleLayoutStyle.ICON_LEFT_TITLE_RIGHT);
// 设置泡泡控件在底部
myInfo.setLocationStyle(LemonBubbleLocationStyle.BOTTOM);
// 设置泡泡控件的动画图标颜色为蓝色
myInfo.setIconColor(Color.BLUE);
// 设置泡泡控件的尺寸,单位dp
myInfo.setBubbleSize(200, 80);
// 设置泡泡控件的偏移比例为整个屏幕的0.01,
myInfo.setProportionOfDeviation(0.01f);
// 设置泡泡控件的标题
myInfo.setTitle("自定义泡泡控件");
// 展示自定义的泡泡控件,并显示2s后关闭
LemonBubble.showBubbleInfo(this, myInfo, 2000);

一顿乱改,我们运行一下程序,发现泡泡控件已经按我们修改的样式显示出来啦:

图片描述

怎么样,是不是很简单?快来体验一下吧~

现在回到文章开始的那几个问题,问题1和问题3已经解决啦,可以使用能任意自定义的LemonBubble作为你项目的泡泡控件替代方案,那么现在解决问题2,Android平台已经找到解决方案了,那iOS平台我用啥呀?不要惊慌,LemonBubble同时支持Android、iOS-ObjectiveC、iOS-Swift三个平台哦!(其实两个月前iOS的两个平台已经支持了,Android版本因为个人实在忙一拖再拖,才发布出来)三个平台的开源项目地址在文末可以找到哦!
那么现在解决问题4,如果有一天你发现LemonBubble出问题了,有惊人的BUG影响你的使用!!!怎么办?答案是来找我!(^o^)/,欢迎您加入LemonKit技术交流群,无论是LemonBubble还是之前发布的LKAcionSheet,来这里,告诉我(群主),我帮你改bug!,或者你可以通过以下任意一种方式联系到我哦!

QQ: 188443213
Email: liuri@lemonsoft.net
LemonKitQQ群:370157608

在这里顺便打一下广告,文中提到的LemonKit是一款全平台的开源极速开发框架,他正在被设计中,也正在开发中,LemonBubble就是其中的一个子项目,致力于打造全平台的函数库、UI库、工具库等等,麻烦各位去Github点一下stars哦!

版本名称 Github地址
LemonBubble4Android https://github.com/1em0nsOft/LemonBubble4Android
LemonBubble4iOS https://github.com/1em0nsOft/LemonBubble
LemonKit Android版本 https://github.com/1em0nsOft/LemonKit4Android
LemonKit iOS ObjC版本 https://github.com/1em0nsOft/LemonKit4iOS
LemonKit iOS Swift版本 https://github.com/1em0nsOft/LemonKit4iOS-Swift

相关源码推荐:

2017-01-17 13:49:23 shineflowers 阅读数 1061

最近做项目,碰到如下的需求:ViewPager分页,如果是6页(包括6页)就用圆点,如果是6页以上就用进度条来切换。前面一种交互方法最常见,用小圆点来表示当前选中的页面,这些小圆点称为导航点,很多App都是这种实现方式。当用户第一次安装或升级应用时,都会利用导航页面告诉用户当前版本的主要亮点,一般情况下当行页面有三部分组成,背景图片,导航文字和滑动的原点,即下面的效果:


这里就不作详细的讲解,大家可以参考我以前写过的博客:

ViewPager实现图片轮翻效果

今天来实现ViewPager进度条切换,主要逻辑如下:

MainActivity.java

package com.jackie.slidebarviewdemo.activity;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

import com.jackie.slidebarviewdemo.R;
import com.jackie.slidebarviewdemo.widget.SlideBarView;

public class MainActivity extends AppCompatActivity {
    private SlideBarView mSlideBarView;
    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mSlideBarView = (SlideBarView) findViewById(R.id.slide_bar);
        mTextView = (TextView) findViewById(R.id.text_view);

        mSlideBarView.setTotalPage(80);
        mSlideBarView.setOnSlideChangeListener(new SlideBarView.OnSlideChangeListener() {
            @Override
            public void onSlideChange(int page) {
                mTextView.setText("当前是第" + page + "页");
            }
        });
    }
}
SlideBarView.java
package com.jackie.slidebarviewdemo.widget;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.jackie.slidebarviewdemo.R;
import com.jackie.slidebarviewdemo.utils.ConvertUtils;

/**
 * Created by Jackie on 2017/1/17.
 */

public class SlideBarView extends RelativeLayout {
    private LayoutInflater mInflater;

    private RelativeLayout mSlideBarView;
    private View mSlideBarBlock;

    private PopupWindow mPopupWindow;
    private TextView mPopupText;

    private int mDp40;

    private String mBound = "no"; // no表示没到边界,left为到左边界了,right表示到右边界了

    public interface OnSlideChangeListener {
        void onSlideChange(int page);
    }

    private OnSlideChangeListener mOnSlideChangeListener;
    public void setOnSlideChangeListener(OnSlideChangeListener onSlideChangeListener) {
        this.mOnSlideChangeListener = onSlideChangeListener;
    }

    public SlideBarView(Context context) {
        this(context, null);
    }

    public SlideBarView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SlideBarView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        init(context);
        initEvent();
    }

    private void init(Context context) {
        mInflater = LayoutInflater.from(context);
        View slideBar = mInflater.inflate(R.layout.slide_bar, null);
        LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        addView(slideBar, params);

        mSlideBarView = (RelativeLayout) slideBar.findViewById(R.id.slide_bar_view);
        mSlideBarBlock = slideBar.findViewById(R.id.slide_bar_block);

        mDp40 = ConvertUtils.dip2px(context, 40);
    }

    private void initEvent() {
        mSlideBarView.setOnTouchListener(new OnTouchListener() {
            int currentX = 0;
            int startX = 0;

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        currentX = (int) event.getX();
                        startX = (int) event.getX();

                        // 设置滑块的滑动, 手指第一次点下去把滑块放到手指上
                        int downLeft = currentX - mSlideBarBlock.getMeasuredWidth() / 2;
                        int downTop = mSlideBarBlock.getTop();
                        int downRight = downLeft + mSlideBarBlock.getWidth();
                        int downBottom = mSlideBarBlock.getBottom();

                        //边界检测
                        if (downLeft < 0) {
                            downLeft = 0;
                            downRight = mSlideBarBlock.getMeasuredWidth();
                        } else if (downRight > mSlideBarView.getMeasuredWidth()) {
                            downLeft = mSlideBarView.getMeasuredWidth() - mSlideBarBlock.getMeasuredWidth();
                            downRight = mSlideBarView.getMeasuredWidth();
                        }

                        mSlideBarBlock.layout(downLeft, downTop, downRight, downBottom);
                        break;
                    case MotionEvent.ACTION_MOVE:
                        currentX = (int) event.getX();
                        int currentPage = currentX * mTotalPage / mSlideBarView.getMeasuredWidth();
                        if (currentPage < 0) {
                            currentPage = 0;
                        } else if (currentPage > mTotalPage) {
                            currentPage = mTotalPage;
                        }

                        // 设置滑块的滑动
                        int moveLeft = currentX - mSlideBarBlock.getMeasuredWidth() / 2;
                        int moveTop = mSlideBarBlock.getTop();
                        int moveRight = moveLeft + mSlideBarBlock.getMeasuredWidth();
                        int moveBottom = mSlideBarBlock.getBottom();

                        //边界处理
                        if (moveLeft < 0) {
                            mBound = "left";

                            moveLeft = 0;
                            moveRight = mSlideBarBlock.getMeasuredWidth();
                        } else if (moveRight >= mSlideBarView.getMeasuredWidth()) {
                            mBound = "right";

                            moveLeft = mSlideBarView.getMeasuredWidth() - mSlideBarBlock.getMeasuredWidth();
                            moveRight = mSlideBarView.getMeasuredWidth();
                        } else {
                            mBound = "no";
                        }

                        mSlideBarBlock.layout(moveLeft, moveTop, moveRight, moveBottom);
                        startX = currentX;

                        //设置popupWindow的弹出位置
                        if (mOnSlideChangeListener != null) {
                            if (currentPage == mTotalPage) {
                                //防止ViewPager越界
                                currentPage = mTotalPage - 1;
                            }

                            mOnSlideChangeListener.onSlideChange(currentPage);

                            if (mPopupWindow != null) {
                                mPopupText.setText(currentPage + "");

                                //设置PopupWindow的滑动
                                if (!mPopupWindow.isShowing()) {
                                    int[] location = new int[2];
                                    mSlideBarView.getLocationInWindow(location);
                                    mPopupWindow.showAsDropDown(mSlideBarView, currentX, location[1] - mDp40);
                                } else {
                                    if ("no".equals(mBound)) {
                                       int[] location = new int[2] ;
                                        mSlideBarView.getLocationInWindow(location);
                                        mPopupWindow.update(currentX, location[1] - mDp40, mPopupWindow.getWidth(), mPopupWindow.getHeight(), true);
                                    }
                                }
                            }
                        }
                        break;
                    case MotionEvent.ACTION_UP:
                        currentX = 0;
                        startX = 0;
                        mPopupWindow.dismiss();
                        break;
                }

                return true;
            }
        });

        // 初始化PopupWindow
        View contentView = mInflater.inflate(R.layout.popup_window, null);
        mPopupText = (TextView) contentView.findViewById(R.id.popup_text);
        mPopupWindow = new PopupWindow(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        mPopupWindow.setContentView(contentView);
        mPopupWindow.setOutsideTouchable(true);
        mPopupWindow.setBackgroundDrawable(getResources().getDrawable(R.mipmap.popup_window_bg));
        mPopupWindow.setAnimationStyle(0);
    }

    int mTotalPage = 0;
    public void setTotalPage(int totalPage) {
        this.mTotalPage = totalPage;
    }
}

相关的单位转化工具,大家可以拷贝到自己的项目中直接使用。

ConvertUtils.java

package com.jackie.slidebarviewdemo.utils;

import android.content.Context;

public class ConvertUtils {
	public static int dip2px(Context context, float dpValue) {
		final float scale = context.getResources().getDisplayMetrics().density;
		return (int) (dpValue * scale + 0.5f);
	}

	public static int px2dip(Context context, float pxValue) {
		final float scale = context.getResources().getDisplayMetrics().density;
		return (int) (pxValue / scale + 0.5f);
	}
	
	public static int px2sp(Context context, float pxValue) {
        final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;  
        return (int) (pxValue / fontScale + 0.5f);  
    } 
	
	public static int sp2px(Context context, float spValue) {
        final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;  
        return (int) (spValue * fontScale + 0.5f);  
    }
}

自定义组合控件,然后实现相关的手势,思路很清晰,代码也很详细,这里就直接贴代码了。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:orientation="vertical">

        <com.jackie.slidebarviewdemo.widget.SlideBarView
            android:id="@+id/slide_bar"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:layout_marginLeft="20dp"
            android:layout_marginRight="20dp"/>

        <TextView
            android:id="@+id/text_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="20dp"
            android:textColor="#000"
            android:textSize="20dp"
            android:text="当前是第0页"/>
    </LinearLayout>
</RelativeLayout>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <RelativeLayout
        android:id="@+id/slide_bar_view"
        android:layout_width="match_parent"
        android:layout_height="50dp">

        <View
            android:layout_width="match_parent"
            android:layout_height="5dp"
            android:layout_centerInParent="true"
            android:background="@drawable/shape_slide_bar_bg"/>

        <View
            android:id="@+id/slide_bar_block"
            android:layout_width="20dp"
            android:layout_height="14dp"
            android:background="#b9b9b9"
            android:layout_centerVertical="true" />
    </RelativeLayout>
</RelativeLayout>
popup_window.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <RelativeLayout
        android:layout_width="30dp"
        android:layout_height="30dp">
        <TextView
            android:id="@+id/popup_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#fff"
            android:textSize="16dp"
            android:gravity="center"
            android:layout_centerInParent="true" />
    </RelativeLayout>
</RelativeLayout>
附上相关的资源文件:

shape_slide_bar_bg.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="#dcdcdc" />
    <corners android:radius="1dp"/>
</shape>

popup_window_bg.9.png



效果如下:



2019-06-20 11:48:59 chuyangchangxi 阅读数 22

一、目标

实现圆环进度条,为神马笔记播放笔记的录音元素做准备。
在这里插入图片描述

二、参考项目

开源项目 描述
ldoublem / RingProgress a circle progress bar with effect
HotBitmapGG / RingProgressBar A material design circle the progress bar.

三、系统功能类

描述
ShapeDrawable 使用各种Shape的Drawable。
ArcShape A material design circle the progress bar.

四、实现代码

添加了start()stop()接口,使之产生动画效果。

public class RingView extends View {

    long duration;
    long progress;

    long startTime;
    long endTime;
    boolean isRunning;

    ShapeDrawable drawable;
    RingShape shape;

    float indentSize;

    public RingView(Context context) {
        this(context, null);
    }

    public RingView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public RingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);

        {
            this.shape = new RingShape(-90, 0);
            this.drawable = new ShapeDrawable(shape);

            float value = 2.6f;
            DisplayMetrics metrics = context.getResources().getDisplayMetrics();
            float strokeWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, metrics);
            this.indentSize = strokeWidth / value;
            indentSize *= 1.4f;

            Paint paint = drawable.getPaint();
            paint.setStyle(Paint.Style.STROKE);
            paint.setColor(Color.WHITE);
            paint.setStrokeWidth(strokeWidth);
            paint.setStrokeCap(Paint.Cap.BUTT);
            paint.setStrokeJoin(Paint.Join.ROUND);
        }

    }

    public void setDuration(long duration) {
        this.duration = duration;

        this.postInvalidate();
    }

    public void setProgress(long progress) {
        this.progress = progress;

        this.postInvalidate();
    }

    public void start() {
        this.startTime = SystemClock.elapsedRealtime();
        this.endTime = startTime;

        this.isRunning = true;

        this.invalidate();

    }

    public void stop() {
        if (!isRunning) {
            return;
        }

        this.endTime = SystemClock.elapsedRealtime();
        this.progress += (this.endTime - this.startTime);

        this.isRunning = false;

        this.invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if (this.getWidth() <= 0 || this.getHeight() <= 0) {
            return;
        }

        {
            this.drawProgress(canvas);
        }

        if (isRunning) {
            this.invalidate();
        }
    }

    void drawProgress(Canvas canvas) {

        long current = this.progress;
        if (isRunning) {
            current += (SystemClock.elapsedRealtime() - this.startTime);
        }

        long total = this.duration;

        {
            float sweepAngle = 0;
            if (total > 0) {
                sweepAngle = 360.f;
                sweepAngle = (current < total)? (360.f * current / total): sweepAngle;
            }

            shape.setSweepAngle(sweepAngle);

        }

        {
            float strokeWidth = this.indentSize;

            int left = (int)strokeWidth;
            int top = (int)strokeWidth;
            int right = (int)(this.getWidth() - strokeWidth);
            int bottom = (int)(this.getHeight() - strokeWidth);
            drawable.setBounds(left, top, right, bottom);
            drawable.draw(canvas);
        }
    }

    /**
     *
     */
    private static class RingShape extends RectShape {
        private float mStartAngle;
        private float mSweepAngle;

        /**
         * RingShape constructor.
         *
         * @param startAngle the angle (in degrees) where the arc begins
         * @param sweepAngle the sweep angle (in degrees). Anything equal to or
         *                   greater than 360 results in a complete circle/oval.
         */
        public RingShape(float startAngle, float sweepAngle) {
            mStartAngle = startAngle;
            mSweepAngle = sweepAngle;
        }

        /**
         * @return the angle (in degrees) where the arc begins
         */
        public final float getStartAngle() {
            return mStartAngle;
        }

        public void setStartAngle(float startAngle) {
            this.mStartAngle = startAngle;
        }

        /**
         * @return the sweep angle (in degrees)
         */
        public final float getSweepAngle() {
            return mSweepAngle;
        }

        public void setSweepAngle(float sweepAngle) {
            this.mSweepAngle = sweepAngle;
        }

        @Override
        public void draw(Canvas canvas, Paint paint) {
            canvas.drawArc(rect(), mStartAngle, mSweepAngle, false, paint);
        }

        @Override
        public void getOutline(Outline outline) {
            // Since we don't support concave outlines, arc shape does not attempt
            // to provide an outline.
        }

        @Override
        public RingShape clone() throws CloneNotSupportedException {
            return (RingShape) super.clone();
        }
    }
}

五、开发过程回顾

实现圆环的核心代码是Canvas#drawArc()方法。

借鉴了ArcShape代码,实现RingShape,并结合ShapeDrawable使用。

六、接下来

组合出录音的RecyclerView的ViewHolder。

继续完成神马笔记录音功能。

七、Finally

须菩提。
若有人言。
如来若来若去。若坐若卧。
是人不解我所说义。
何以故。
如来者。
无所从来。亦无所去。
故名如来。

没有更多推荐了,返回首页