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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章