返回

多元花样之自定义View选择时间控件

Android

楔子

自定义View是一个神奇的技术,它可以从简单到复杂,从一个控件的组合到动画、矩阵操作的结合。有人看到视觉稿中从未见过的新控件而感到恐慌,也有人觉得自定义控件很有成就感。作为一名合格的Android高级工程师,自定义View乃是必经之路。

探秘自定义View

从简单到复杂

自定义View可以很简单,例如只需组合几个控件就可以实现一个简单的时钟控件。

也可以很复杂,例如实现一个可以旋转的3D地球控件,就需要用到动画和矩阵操作。

扩展Android控件

自定义View可以扩展Android的原生控件,例如可以实现一个带有日历功能的EditText控件。

也可以实现一个可以拖动的ListView控件。

构建全新控件

自定义View还可以构建全新的控件,例如可以实现一个可以显示饼图的控件。

也可以实现一个可以显示甘特图的控件。

自定义View挑战与收获

挑战

自定义View最大的挑战在于性能优化,因为自定义View需要自己管理内存和绘制,如果优化不当很容易导致性能问题。

收获

自定义View最大的收获在于成就感,因为自己动手实现一个控件是一件很有成就感的事情。

此外,自定义View还可以帮助我们更深入地理解Android的图形系统。

为何必要自定义控件?

  1. 满足项目特殊需求

Android原生控件无法满足项目的需求,需要自定义控件来实现特殊的功能。

  1. 提升用户体验

自定义控件可以为用户提供更好的交互体验,例如自定义控件可以实现更流畅的动画效果或更直观的交互方式。

  1. 提高开发效率

自定义控件可以提高开发效率,例如自定义控件可以减少代码量或提高代码的可重用性。

  1. 实现项目差异化

自定义控件可以帮助项目实现差异化,例如自定义控件可以使项目看起来更独特或更符合项目的需求。

窥探自定义控件之时间选择

时间选择控件

时间选择控件是Android中常用的控件,它可以帮助用户选择日期和时间。

Android原生提供了两个时间选择控件:DatePicker和TimePicker。

DatePicker可以用来选择日期,TimePicker可以用来选择时间。

自定义时间选择控件

Android原生的时间选择控件功能简单,样式单一,如果项目需要更复杂或更美观的日期选择控件,就需要自定义时间选择控件。

如何自定义时间选择控件

自定义时间选择控件可以分为以下几个步骤:

  1. 创建一个新的View类

  2. 在View类的onDraw()方法中绘制时间选择控件

  3. 在View类的onTouchEvent()方法中处理用户交互

自定义时间选择控件案例

优雅多选之年、月、日、时、分选择器

场景

项目需要一个可以同时选择年、月、日、时、分的控件,而Android原生控件无法满足此需求。

实现

自定义了一个YearMonthDayHourMinutePicker控件,该控件可以同时选择年、月、日、时、分。

控件的样式如下:

YearMonthDayHourMinutePicker控件样式

控件的代码如下:

public class YearMonthDayHourMinutePicker extends View {

    private int mYear;
    private int mMonth;
    private int mDay;
    private int mHour;
    private int mMinute;

    private Paint mPaint;
    private Rect mBounds;

    public YearMonthDayHourMinutePicker(Context context) {
        super(context);

        mPaint = new Paint();
        mPaint.setTextSize(40);
        mPaint.setColor(Color.BLACK);

        mBounds = new Rect();
    }

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

        // 绘制年
        String year = String.valueOf(mYear);
        mPaint.getTextBounds(year, 0, year.length(), mBounds);
        canvas.drawText(year, (getWidth() - mBounds.width()) / 2, (getHeight() - mBounds.height()) / 2, mPaint);

        // 绘制月
        String month = String.valueOf(mMonth);
        mPaint.getTextBounds(month, 0, month.length(), mBounds);
        canvas.drawText(month, (getWidth() - mBounds.width()) / 2, (getHeight() - mBounds.height()) / 2 + mBounds.height(), mPaint);

        // 绘制日
        String day = String.valueOf(mDay);
        mPaint.getTextBounds(day, 0, day.length(), mBounds);
        canvas.drawText(day, (getWidth() - mBounds.width()) / 2, (getHeight() - mBounds.height()) / 2 + 2 * mBounds.height(), mPaint);

        // 绘制时
        String hour = String.valueOf(mHour);
        mPaint.getTextBounds(hour, 0, hour.length(), mBounds);
        canvas.drawText(hour, (getWidth() - mBounds.width()) / 2, (getHeight() - mBounds.height()) / 2 + 3 * mBounds.height(), mPaint);

        // 绘制分
        String minute = String.valueOf(mMinute);
        mPaint.getTextBounds(minute, 0, minute.length(), mBounds);
        canvas.drawText(minute, (getWidth() - mBounds.width()) / 2, (getHeight() - mBounds.height()) / 2 + 4 * mBounds.height(), mPaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 按下时获取触摸点坐标
                float x = event.getX();
                float y = event.getY();

                // 判断触摸点是否在控件范围内
                if (x >= 0 && x <= getWidth() && y >= 0 && y <= getHeight()) {
                    // 如果在控件范围内,则获取触摸点所在的区域
                    int region = (int) (y / (getHeight() / 5));

                    // 根据触摸点所在的区域,设置相应的年份、月份、日期、小时、分钟
                    switch (region) {
                        case 0:
                            mYear = mYear + 1;
                            break;
                        case 1:
                            mMonth = mMonth + 1;
                            break;
                        case 2:
                            mDay = mDay + 1;
                            break;
                        case 3:
                            mHour = mHour + 1;
                            break;
                        case 4:
                            mMinute = mMinute + 1;
                            break;
                    }

                    // 刷新控件
                    invalidate();
                }

                break;
        }

        return true;
    }
}

结语

自定义控件是Android开发中一项高级技能,它可以帮助我们实现更复杂、更美观、更符合项目需求的控件。

自定义控件虽然挑战重重,但只要掌握了方法和技巧,就能轻松驾驭。