仿锤子滚轮控件

仿锤子滚轮控件

锤子控件样式:

这里写图片描述
动图效果:
百度云盘-hammer.mp4

手写控件样式:

这里写图片描述
动图效果:
百度云盘-address.mp4

  • 感觉模糊可以下载下来播放
思路:

通过总滚动量来绘制界面, 所有的touch操作只改变滚动量

//当前选中的index与偏移量等变量均由这个变量计算得,若要改变index请改变totalScroll
float totalScroll;//一共滚动了多少,由于是向上滑动,所以这个数一直都是一个负数
绘制:

中间那一栏的高度允许与旁边的不同
中间那一栏的文字在滚动时, 字体大小和颜色会渐变

float percent = Math.abs(itemScroll) / side_text_height;
textPaint.setColor(MathUtils.caculateColor(side_text_color, center_text_color, percent));
textPaint.setTextSize(MathUtils.caculateFloat(side_text_size, center_text_size, percent));
手势操作:
  • 按下时结束所有滚动
if (!overScroller.isFinished()) {
    overScroller.abortAnimation();
}
  • 移动时滚轮跟着动
float currentY = event.getY();
totalScroll += currentY - moveMarkY;//由于向上滑,y变小,但是totalScroll变大, 所以取负
//防止越界
if (totalScroll > 0) {
    totalScroll = 0;
}
if (totalScroll < -1 * (mAdapter.getCount() - 1) * side_text_height) {
    totalScroll = -1 * (mAdapter.getCount() - 1) * side_text_height;
}
//重绘,绘制时会根据totalScroll计算当前item
invalidate();
  • 手指移开时触发fling
if (absVelocity > mMinimumVelocity) {
    int maxY;
    if (yVelocity < 0) {
        //手指向上,滚轮向上,maxY为数据总量的高度-已滚动的量
        maxY = (int) Math.abs(-1 * side_text_height * (mAdapter.getCount() - 1) - totalScroll);
        scrollDirectionUp = true;
    } else {
        //手指向上,滚轮向上,maxY为0+已滚动量
        maxY = (int) Math.abs(totalScroll);
        scrollDirectionUp = false;
    }
    Log.i(TAG, "onTouchEvent: maxY= " + maxY);
    //fling的scroll方法可以是负数,但是fling方法的velocity必须是正数,
    //从而导致maxY必然大于startY,也就是说,还需要一个变量记录fling的方向
    scrollMarkY = 0;//重置滚动标记并开始滚动
    currentScrollType = SCROLL_TYPE_FLING;
    overScroller.fling(0, 0, 0, absVelocity, 0, 0, 0, maxY);
}
  • 偏移量矫正
//微调任务
private void autoAdjustByScroll() {
    //似乎马上执行的话,itemScroll会有概率不准确,改为延时任务
    TimerTask timerTask = new TimerTask() {
        @Override
        public void run() {
        scrollMarkY = 0;
        int itemScrollInt = (int) itemScroll;
        float scrollPercent = itemScrollInt * 1.0f / side_text_height;
        int duration = (int) Math.abs(1000 * scrollPercent);
        currentScrollType = SCROLL_TYPE_ADJUST;
        overScroller.startScroll(0, 0, 0, -itemScrollInt, duration);
        postInvalidate();//线程中刷新要调用postInvalidate
        }
    };
    Timer timer = new Timer();
    timer.schedule(timerTask, 20);
}
封装:
  • 基类 BasePicker
    带有标题, 确定和取消按钮, 另外提供两个抽象方法, 用于改变整体样式和滚轮样式
    /**
     * 可以通过继承来改变布局的样式, 新布局要求:
     * <p>一个id为tv_cancel的TextView,用于返回</p>
     * <p>一个id为tv_title的TextView,用于显示标题</p>
     * <p>一个id为tv_commit的TextView,用于提交</p>
     * <p>一个id为fl_content的FrameLayout,用于嵌套滚轮控件</p>
     */
    protected int getContentLayout() {
        return 0;
    }

    /**
     * 可以通过继承来改变滚轮的样式,新布局要求:
     * <p>只有一个WheelView</p>
     * <p>宽为0px</p>
     * <p>高最好为wrap_content</p>
     */
    protected int getWheelViewLayout() {
        return 0;
    }
  • 日期 DatePicker
    填充日期数据, 并提供6种模式: 年、月、日、年+月、月+日、年+月+日
public static final int MODE_YEAR_ONLY = 0x0100;
public static final int MODE_MONTH_ONLY = 0x0010;
public static final int MODE_DAY_ONLY = 0x0001;
public static final int MODE_YEAR_MONTH = 0x0110;
public static final int MODE_MONTH_DAY = 0x0011;
public static final int MODE_YEAR_MONTH_DAY = 0x0111;

public void setMode(int mode) {
    boolean showYear = (mode & 0x0100) != 0;
    boolean showMonth = (mode & 0x0010) != 0;
    boolean showDay = (mode & 0x0001) != 0;
    int yearVisibility = showYear ? View.VISIBLE : View.GONE;
    int monthVisibility = showMonth ? View.VISIBLE : View.GONE;
    int dayVisibility = showDay ? View.VISIBLE : View.GONE;
    dateWheelView.setVisibility(yearVisibility, monthVisibility, dayVisibility);
}
  • 选项 OptionPicker
    泛型, 自定义数据
private ArrayList<T> leftData;
private ArrayList<ArrayList<T>> middleData;
private ArrayList<ArrayList<ArrayList<T>>> rightData;

public interface OnOptionSelectedListener {
    public void onOptionSelected(int leftPosition, int middlePosition, int rightPosition);
}
  • 选项数据模型T
    请实现OptionText接口, 或者改写toString()方法
public interface OptionText {
    public String getOptionText();
}

public String getText(int position) {
    T t = data.get(position);
    if (t instanceof OptionText) {
        OptionText optionText = (OptionText) t;
        return optionText.getOptionText();
    } else {
        return t.toString();
    }
}
项目地址:

HammerPickerViewDemo

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值