自定义DateView控件

2014-11-21

最近因为项目需要自定义一个日期控件,我花了一个多小时写了这个控件。虽然跟设计效果图还有点细微差别,但是这个可以慢慢修改。

效果图1 效果图1

    public class DateView extends View {

    private static final int DAY_TEXT_SIZE = 32;
    private static final int MONTH_TEXT_SIZE = 16;

    private int mDay;
    private int mMonth;
    private int mYear;

    private TextPaint mDayPaint;
    private TextPaint mMonthPaint;

    public DateView(Context context) {
        super(context);
        initView();
    }

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

    public DateView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    private void initView() {
        mDayPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
        mDayPaint.setColor(0xff333333);
        mMonthPaint = new TextPaint(mDayPaint);
        mDayPaint.setTextSize(dip2px(getContext(), DAY_TEXT_SIZE));
//        setBackgroundColor(Color.TRANSPARENT);
        setDate(Calendar.getInstance().getTimeInMillis()/1000);
        setMinimumWidth(dip2px(getContext(),80));
        setMinimumHeight(dip2px(getContext(), 80));
    }

    /**
     * 显示年月日
     * @param timeInSeconds 以秒为单位
     */
    public void setDate(long timeInSeconds) {
        Calendar ca = Calendar.getInstance();
        ca.clear();
        ca.setTimeInMillis(timeInSeconds *1000);
        mMonth = ca.get(Calendar.MONTH) + 1;
        mYear = ca.get(Calendar.YEAR);
        mDay = ca.get(Calendar.DAY_OF_MONTH);
        mMonthPaint.setTextSize(dip2px(getContext(), MONTH_TEXT_SIZE));
        invalidate();
    }

    /**
     * 设置时间,当year为0时,表示不需要显示年,只显示月日
     * @param day 1-31
     * @param month 1-12
     * @param year >= 0,0表示不显示年
     */
    public void setDate(int day, int month, int year) {
        mDay = day;
        mMonth = month;
        if (mMonth == 0) mMonth = 1;
        mYear = year;
        if (mYear == 0) {
            mMonthPaint.setTextSize(dip2px(getContext(), MONTH_TEXT_SIZE+2));
        } else {
            mMonthPaint.setTextSize(dip2px(getContext(), MONTH_TEXT_SIZE));
        }
        invalidate();
    }

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

    public void setTextColor(int color) {
        mDayPaint.setColor(color);
        mMonthPaint.setColor(color);
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        String dayText = String.valueOf(String.format("%02d", mDay));
        int dayTextLen = (int) mDayPaint.measureText(dayText);

        int canvasWith = canvas.getWidth();
        int canvasHeight = canvas.getHeight();

        canvas.drawLine(canvasWith*0.75f, canvasHeight*0.25f, canvasWith*0.25f, canvasHeight*0.75f, mDayPaint);

        canvas.drawText(dayText, canvasWith/2-dayTextLen, canvasHeight/2+mDayPaint.getFontMetrics().descent/2, mDayPaint);


        Paint.FontMetrics fontMetrics = mMonthPaint.getFontMetrics();


        String monthText = String.valueOf(mMonth) + "月";
//        int monthTextLen = (int)mMonthPaint.measureText(monthText);
        float textHeight = Math.abs(fontMetrics.ascent) + Math.abs(fontMetrics.descent) + fontMetrics.leading;
        if (mYear > 0) {
            String yearText = String.valueOf(mYear);
            canvas.drawText(yearText, canvasWith/2 - mMonthPaint.getTextSize()*0.5f, canvasHeight/2 + mMonthPaint.getTextSize()*1.5f, mMonthPaint);
            canvas.drawText(monthText, canvasWith/2 + mMonthPaint.getTextSize()/2, canvasHeight/2+mMonthPaint.getTextSize()*0.5f, mMonthPaint);
        } else {
            canvas.drawText(monthText, canvasWith/2, canvasHeight/2+mMonthPaint.getTextSize(), mMonthPaint);
        }
    }
}

这最不好做的就是算字的位置,文字的渲染是基于baseline的,我的理解是Rect的左下角。关于canvas的draw还有很多不懂,好好学习

Category: Android Tagged: Android 自定义控件 日期控件

Comments