Android笔记--仿拖动选择日期时间控件的单个item

效果图如下:

因为需要做一个类似闹钟的功能,系统自带的,虽然7.0包的那个圆盘看着是挺好看的,挺高大上的,但真心不太好用,然后网上找的时候,找到了一个比较精美的日期选择控件,但是奈何她写的模式固定死了,仅仅是可以选择年月日时分,或者是月日,偏偏我需要的时分模式没有,而且是写好了弹窗的形式,与我需要的嵌入到布局中的需求也不太符合,所以干脆是操刀自己仿来写一个了。(她写的日期传送门:https://github.com/mrfluency/Time-Selector)

目前写了一个可拖动可定制的item,然后通过这个item就可以把日期、时间选择的都集成出来了,集成的传送门:https://my.oschina.net/u/1462828/blog/861817,直接上代码:

package com.imxiaoyu.common.widget;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.imxiaoyu.common.impl.OnStringListener;

import java.util.ArrayList;
import java.util.List;

/**
 * 自定义时间选择
 * Created by 庞光渝 on 2017/3/9.博客:https://my.oschina.net/u/1462828/blog
 */

public class PickerItemView extends View {

    /**
     * 变量
     */
    private List<ItemEntity> itemEntities;
    private float startY = 0;//记录手指按下时候的Y坐标
    private float itemHeight = 0;//每一个文本的高度(包括上下空白的地方)
    private float minFontSize;//最小的文字字体大小
    private float maxFontSize;//最大的文字字体大小
    private boolean isLoop = false;//是否循环
    private String lastValue;//
    //用于根据高度设置最小最大文字的大小,范围2-80;
    private int minFontSizePercent = 35;
    private int maxFontSizePercent = 65;
    private int normalFontColor = 0xff999999;//正常的文字颜色
    private int pressFontColor = 0xff444444;//选中的文字颜色

    /**
     * 外部接口
     */
    private OnStringListener onPitchOnChangeListener;//拖动的时候,返回当前选中的

    public PickerItemView(Context context) {
        super(context);
    }

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

    public PickerItemView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        itemHeight = getHeight() / 5;
        minFontSize = itemHeight * minFontSizePercent / 100;
        maxFontSize = itemHeight * maxFontSizePercent / 100;
        if (itemEntities != null) {
            drawText(canvas);
        }
    }

    /**
     * 重写触摸监听
     *
     * @param event
     * @return
     */
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                startY = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                float y = event.getY() - startY;
                startY = event.getY();
                deviationY(y);
                onPitchOnBack();
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                //手指抬起的时候,计算并偏移Y轴,相当于对齐一下位置,让被选中的那个保持在画布中间
                if (itemEntities != null && itemEntities.size() > 0) {
                    float intervalY = (itemEntities.get(0).getY()) % itemHeight;
                    intervalY = (intervalY + itemHeight * 2) % itemHeight;
                    if (intervalY >= itemHeight / 2) {
                        deviationY((itemHeight - intervalY));
                    } else {
                        deviationY(-intervalY);
                    }
                    onPitchOnBack();
                    invalidate();
                }
                break;
        }
        return true;
    }


    /**
     * 绘制文本
     *
     * @param canvas
     */
    private void drawText(Canvas canvas) {
        for (int i = 0; i < itemEntities.size(); i++) {
            ItemEntity itemEntity = itemEntities.get(i);
            if ((itemEntity.getY() > (-itemHeight)) && itemEntity.getY() < itemHeight * 6) {
                //在范围内,绘制出来
                float itemCoreY = itemEntity.getY() + itemHeight / 2;
                float itemCoreX = getWidth() / 2;
                float size = getFontSize(itemEntity.getY());
                int color = normalFontColor;
                if (size == maxFontSize) {
                    color = pressFontColor;
                }
                Bitmap bitmap = str2Bitmap(itemEntity.getValue(), (int) size, color);
                float x = itemCoreX - bitmap.getWidth() / 2;
                float y = itemCoreY - bitmap.getHeight() / 2;
                canvas.drawBitmap(bitmap, x, y, null);
            }
        }
    }

    /**
     * 将文本绘制成一个bitmap,并居中
     *
     * @param testString
     * @param size
     * @param txtColor
     * @return
     */
    public Bitmap str2Bitmap(String testString, int size, int txtColor) {
        float x = size * testString.length() + 1;
        float y = size + 1;
        Bitmap bmp = Bitmap.createBitmap((int) x, (int) y, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bmp);
        Rect targetRect = new Rect(0, 0, (int) x, (int) y);
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setTextSize(size);
        paint.setColor(txtColor);
        Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt();
        int baseline = (targetRect.bottom + targetRect.top - fontMetrics.bottom - fontMetrics.top) / 2;
        paint.setTextAlign(Paint.Align.CENTER);
        canvas.drawText(testString, targetRect.centerX(), baseline, paint);
        return bmp;
    }

    /**
     * Y 轴偏移,即移动
     *
     * @param y
     */
    private void deviationY(float y) {
        if (itemEntities == null || itemEntities.size() <= 0) {
            return;
        }
        if (isLoop) {
            //可以循环
            if (y > 0) {
                //往下拉
                if ((itemEntities.get(0).getY() + y) >= -itemHeight) {
                    ItemEntity itemEntity = itemEntities.get(itemEntities.size() - 1);
                    itemEntities.remove(itemEntities.size() - 1);
                    itemEntity.setY(itemEntities.get(0).getY() - itemHeight);
                    itemEntities.add(0, itemEntity);
                }
            } else {
                //往下拉
                if ((itemEntities.get(itemEntities.size() - 1).getY() + y) <= itemHeight * 6) {
                    ItemEntity itemEntity = itemEntities.get(0);
                    itemEntities.remove(0);
                    itemEntity.setY(itemEntities.get(itemEntities.size() - 1).getY() + itemHeight);
                    itemEntities.add(itemEntities.size(), itemEntity);
                }
            }
        } else {
            //不可以循环,上下到顶了就不给滑了
            if ((itemEntities.get(0).getY() + y) > itemHeight * 2) {
                return;
            }
            if ((itemEntities.get(itemEntities.size() - 1).getY() + y) < itemHeight * 2) {
                return;
            }
        }

        for (int i = 0; i < itemEntities.size(); i++) {
            itemEntities.get(i).setY(itemEntities.get(i).getY() + y);
        }
    }

    /**
     * 计算Y轴不同位置的需要映射的字体大小
     *
     * @param y
     * @return
     */
    private float getFontSize(float y) {
        y = y + itemHeight / 2;
        if (y <= itemHeight / 2 || y > 4.5 * itemHeight) {
            return minFontSize;
        }
        if (y > itemHeight / 2 && y < itemHeight * 2) {
            //慢慢大
            return (float) ((maxFontSize - minFontSize) * (y - (itemHeight / 2)) / (1.5 * itemHeight) + minFontSize);
        }
        if (y >= itemHeight * 2 && y <= itemHeight * 3) {
            return maxFontSize;
        }
        if (y > itemHeight * 3 && y <= 4.5 * itemHeight) {
            //慢慢小
            return (float) (maxFontSize - (maxFontSize - minFontSize) * (y - itemHeight * 3) / (1.5 * itemHeight));
        }
        return minFontSize;
    }

    /**
     * 改变值的时候回调通知
     */
    private void onPitchOnBack() {
        if (onPitchOnChangeListener != null) {
            String str = getPitchOn();
            if (!str.equals(lastValue)) {
                lastValue = str;
                onPitchOnChangeListener.onClick(str);
            }
        }
    }

    /**
     * 设置数组
     *
     * @param strings
     */
    public void setList(final List<String> strings) {
        if (strings == null || strings.size() <= 0) {
            return;
        }
        if (strings.size() < 9) {
            isLoop = false;
        } else {
            isLoop = true;
        }
        post(new Runnable() {
            @Override
            public void run() {
                itemHeight = getHeight() / 5;
                itemEntities = new ArrayList<>();
                for (int i = 0; i < strings.size(); i++) {
                    ItemEntity itemEntity = new ItemEntity();
                    itemEntity.setValue(strings.get(i));
                    itemEntity.setY(itemHeight * i);
                    itemEntities.add(itemEntity);
                }
                invalidate();
            }
        });
    }

    /**
     * 设置是否循环,如果小于9条记录,直接默认不给循环,必须在setList()之后调用,因为setList会有一个自动设置是否循环的动作
     *
     * @param bln
     */
    private void setIsLoop(boolean bln) {
        isLoop = bln;
        if (itemEntities.size() < 9) {
            isLoop = false;
        }
    }

    /**
     * 设置文字颜色
     *
     * @param normal 未选中颜色
     * @param press  选中颜色
     */
    public void setFontColor(int normal, int press) {
        normalFontColor = normal;
        pressFontColor = press;
    }


    /**
     * 根据高度设置最大最小字体的大小,范围是20-80
     *
     * @param minPercent
     * @param maxPercent
     */
    public void setFontSize(int minPercent, int maxPercent) {
        if (minPercent < 20) {
            minPercent = 20;
        }
        if (maxPercent < 20) {
            maxPercent = 20;
        }
        if (minPercent > 80) {
            minPercent = 80;
        }
        if (maxPercent > 80) {
            maxPercent = 80;
        }
        minFontSizePercent = minPercent;
        maxFontSizePercent = maxPercent;
        invalidate();
    }

    /**
     * 设置改变监听
     *
     * @param onStringListener
     */
    public void setOnPitchOnChangeListener(OnStringListener onStringListener) {
        this.onPitchOnChangeListener = onStringListener;
    }

    /**
     * 返回选中的
     *
     * @return
     */
    public String getPitchOn() {
        if (itemEntities != null) {
            for (int i = 0; i < itemEntities.size(); i++) {
                if (itemEntities.get(i).getY() >= 2 * itemHeight && itemEntities.get(i).getY() < 3 * itemHeight) {
                    return itemEntities.get(i).getValue();
                }
            }
        }
        return "";
    }

    class ItemEntity {
        private String value;//需要显示的文本
        private float y;//当前的y坐标

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }

        public float getY() {
            return y;
        }

        public void setY(float y) {
            this.y = y;
        }
    }

}

回调接口:

package com.imxiaoyu.common.impl;

/**
 * 回调一个字符串
 * Created by 她叫我小渝 on 2016/11/1.
 */

public interface OnStringListener {
    void onClick(String str);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值