android自定义时间选择器

在自己项目中有这样一个需求,要把一天分为上午下午晚上三个时间段,把一周分为7天,进行时间选择的一个需求,这样可以比较直观的选择,不必像原来程序那样,手动直接输入,回便捷很多,我先上图,后续慢慢道来!


图片所示的就是我们代码所产生的效果了!

那么我来说明一下我自己的实现思路,核心的问题就是自定义View并绘制!

首先要建立实体类:

package cn.sdut.lsy.time.chooser;

/**
 * Created by lsy on 15-8-10.
 */
public class TimerChoosen {

    private int fromX;

    private int fromY;

    private int toX;

    private int toY;

    private int timeId; // 时间选择位置

    private String timeFree; // 存储的时间状态

    private boolean isChoosen = false; // 是否被选中

    private int fromTimeNum; // 设置是哪个时间段开始
                             // 划分三个时间段,早上,下午,晚上,对应1,2,3三个位置

    private int weekday; // 属于周几

    public void setPoint(int fromX, int fromY, int toX, int toY) {
        this.fromX = fromX;
        this.fromY = fromY;
        this.toX = toX;
        this.toY = toY;
    }

    public int getFromX() {
        return fromX;
    }

    public void setFromX(int fromX) {
        this.fromX = fromX;
    }

    public int getFromY() {
        return fromY;
    }

    public void setFromY(int fromY) {
        this.fromY = fromY;
    }

    public int getToX() {
        return toX;
    }

    public void setToX(int toX) {
        this.toX = toX;
    }

    public int getToY() {
        return toY;
    }

    public void setToY(int toY) {
        this.toY = toY;
    }

    public int getWeekday() {
        return weekday;
    }

    public void setWeekday(int weekday) {
        this.weekday = weekday;
    }

    public int getTimeId() {
        return timeId;
    }

    public void setTimeId(int timeId) {
        this.timeId = timeId;
    }

    public String getTimeFree() {
        return timeFree;
    }

    public void setTimeFree(String timeFree) {
        this.timeFree = timeFree;
    }

    public int getFromTimeNum() {
        return fromTimeNum;
    }

    public void setFromTimeNum(int fromTimeNum) {
        this.fromTimeNum = fromTimeNum;
    }

    public boolean isChoosen() {
        return isChoosen;
    }

    public void setIsChoosen(boolean isChoosen) {
        this.isChoosen = isChoosen;
    }

    @Override
    public String toString() {
        return "+++"+timeFree+"---"+fromTimeNum+"***"+weekday;
    }
}
fromX,fromY,toX,toY是确定位置的主要因素,其他的不多说了,下面是这一个项目中最核心的代码。

/**
 * @author lsy
 * date : 2015年8月10日
 */
package cn.sdut.lsy.time.chooser;

import com.yxw.schedule.ClassInfo;
import com.yxw.schedule.R;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;

import java.util.List;

public class ScheduleViewTime extends View implements OnTouchListener {

    private Paint mPaint; // 画笔,包含了画几何图形、文本等的样式和颜色信息

    private int startX = 0;//画布的原点X(所有的画图操作,都是基于这个原点的,touch中只要修改这个值)

    private int startY = 0;//画布的原点Y(所有的画图操作,都是基于这个原点的,touch中只要修改这个值)

    private static final int sidewidth = 100;//左边,上面bar的宽度

    private static final int eachBoxH = 120;//每个格子的高度

    private static int eachBoxW = 120;//每个格子的宽度,后面根据屏幕对它做了均分

    private int focusX = -1;//当前手指焦点的位置坐标

    private int focusY = -1;//当前手指焦点的位置坐标

    //private static int classTotal = 12;//左边栏总格子数

    private static int timeTotal = 3; // 三个时间段,左边栏总格子数目

    private static int dayTotal = 7;//顶部栏总共格子数

    private String[] weekdays;//星期

    private boolean isMove = false; // 判断是否移动

    private Context context;

    // 监听器
    private OnItemTimeClickListener onItemClassClickListener;

    // 数据
    private List<TimerChoosen> timeChoosens;

    // 颜色
   // public static final int contentBg = Color.argb(255, 255, 255, 255);

    public static final int barBg = Color.argb(255, 225, 225, 225);

   // public static final int bayText = Color.argb(255, 150, 150, 150);

    public static final int barBgHrLine = Color.argb(255, 150, 150, 150);

    public static final int classBorder = Color.argb(180, 150, 150, 150);

    public static final int markerBorder = Color.argb(100, 150, 150, 150);

    //预设格子背景颜色数组
    public static final int[] classBgColors = {Color.argb(200, 71, 154, 199),
            Color.argb(200, 230, 91, 62), Color.argb(200, 50, 178, 93),
            Color.argb(200, 255, 225, 0), Color.argb(200, 102, 204, 204),
            Color.argb(200, 51, 102, 153), Color.argb(200, 102, 153, 204)

    };

    public ScheduleViewTime(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        weekdays = context.getResources().getStringArray(R.array.weekdays);
        mPaint = new Paint();
        setOnTouchListener(this);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        eachBoxW = (getWidth() - sidewidth) / 5;
        printMarker(canvas);
        printContent(canvas);
        printTopBar(canvas);
        printLeftBar(canvas);
    }

    /**
     * 区分课间隔,画交线处的十字
     *
     * @param canvas
     */
    private void printMarker(Canvas canvas) {
        mPaint.setColor(markerBorder);
        for (int i = 0; i < dayTotal - 1; i++) { // 按天
            for (int j = 0; j < timeTotal - 1; j++) { // 按上课节数
                // 画交线处的十字
                mPaint.setStyle(Style.STROKE);
                // 横向
                canvas.drawRect(startX + sidewidth + eachBoxW * (i + 1)
                        - eachBoxW / 20, startY + sidewidth + eachBoxH
                        * (j + 1) - 1, startX + sidewidth + eachBoxW * (i + 1)
                        + eachBoxW / 20, startY + sidewidth + eachBoxH
                        * (j + 1), mPaint);
                // 纵向
                canvas.drawRect(
                        startX + sidewidth + eachBoxW * (i + 1) - 1,
                        startY + sidewidth + eachBoxH * (j + 1) - eachBoxW / 20,
                        startX + sidewidth + eachBoxW * (i + 1), startY
                                + sidewidth + eachBoxH * (j + 1) + eachBoxW
                                / 20, mPaint);
            }
        }
    }

    /**
     * 画中间主体部分
     *
     * @param canvas
     */
    private void printContent(Canvas canvas) {
        if (timeChoosens != null && timeChoosens.size() > 0) {
            mPaint.setTextSize(25); // 设置字体大小
            TimerChoosen timerChoosen;
            for (int i = 0; i < timeChoosens.size(); i++) {
                timerChoosen = timeChoosens.get(i);
               // Log.d("TAG",timerChoosen.toString());
                int fromX = startX + sidewidth + eachBoxW
                        * (timerChoosen.getWeekday() - 1);
                int fromY = startY + sidewidth + eachBoxH
                        * (timerChoosen.getFromTimeNum() - 1);
                int toX = startX + sidewidth + eachBoxW
                        * timerChoosen.getWeekday();
                int toY = startY + sidewidth + eachBoxH
                        * (timerChoosen.getFromTimeNum());
                timerChoosen.setPoint(fromX, fromY, toX, toY); // 存储范围数据

                // 画classbg
                mPaint.setStyle(Style.FILL);
                // 确定颜色
                if(timerChoosen.isChoosen()) {
                    mPaint.setColor(classBgColors[1]);
                } else {
                    mPaint.setColor(classBgColors[2]);
                }
                canvas.drawRect(fromX, fromY, toX - 2, toY - 2, mPaint);
                // 画文字
                mPaint.setColor(Color.WHITE);
                String className = timerChoosen.getTimeFree();
                Rect textRect1 = new Rect();
                mPaint.getTextBounds(className, 0, className.length(),
                        textRect1);
                int th = textRect1.bottom - textRect1.top;
                int tw = textRect1.right - textRect1.left;
                //计算行数
                int row = (int) ((tw + 30) / eachBoxW + 1);
                int length = className.length() / row;
                //逐行写字
                for (int j = 0; j < row - 1; j++) {
                    canvas.drawText(className, length * j, length * (j + 1),
                            fromX + 5, fromY + 10 + th * (j + 1), mPaint);
                }
                //最后一行文字特殊处理
                canvas.drawText(className, length * (row - 1),
                        className.length(), fromX + 15, fromY + 20 + th * row,
                        mPaint);
                // 画边框
                mPaint.setColor(classBorder);
                mPaint.setStyle(Style.STROKE);
                canvas.drawRect(fromX, fromY, toX - 2, toY - 2, mPaint);
            }
        }
    }

    /**
     * 画左边课时bar
     *
     * @param canvas
     */
    private void printLeftBar(Canvas canvas) {
        // =================画左边课时栏=================
        mPaint.setColor(barBg);
        mPaint.setStyle(Style.FILL);
        mPaint.setTextSize(30);
        // 课时栏背景
        canvas.drawRect(0, startY + sidewidth, sidewidth, sidewidth + startY
                + eachBoxH * timeTotal, mPaint);
        mPaint.setColor(barBgHrLine);
        // 画第一个边框线
        canvas.drawRect(0, startY + sidewidth + eachBoxH - 1, sidewidth, startY
                + eachBoxH + sidewidth, mPaint);
        // 居中处理
        Rect textRect1 = new Rect();
        mPaint.getTextBounds("1", 0, 1, textRect1);
        int th = textRect1.bottom - textRect1.top;
        int tw1 = textRect1.right - textRect1.left;
        mPaint.getTextBounds("10", 0, 2, textRect1);
        int tw2 = textRect1.right - textRect1.left;
        // 画第一个文字
        canvas.drawText("上午", sidewidth / 2 - tw1 - th/2, startY + sidewidth + eachBoxH
                / 2 + th / 2, mPaint);
        for (int i = 2; i < timeTotal + 1; i++) {
            String textGet = "";
            // 画边框
            canvas.drawRect(0, startY + sidewidth + eachBoxH * (i-1) - 1,
                    sidewidth, startY + eachBoxH * (i-1) + sidewidth, mPaint);
            // 画文字
            int tw = tw1 * 2 + (tw2 - tw1) * (i / 10);
            if(i == 2) {
                textGet = "下午";
            } else {
                textGet = "晚上";
            }
            canvas.drawText(textGet, sidewidth / 2 - tw / 2 - th / 2, startY + sidewidth
                    + eachBoxH * (i - 1) + eachBoxH / 2 + th / 2, mPaint);
        }
        // =========左上角正方形============
        canvas.drawRect(0, 0, sidewidth, sidewidth, mPaint);
    }

    /**
     * 画顶部星期bar
     *
     * @param canvas
     */
    private void printTopBar(Canvas canvas) {
        // =================画顶部星期栏==================
        mPaint.setColor(barBg);
        mPaint.setStyle(Style.FILL);
        // 星期栏背景
        canvas.drawRect(startX + sidewidth, 0, sidewidth + startX + eachBoxW
                * dayTotal, sidewidth, mPaint);
        mPaint.setColor(barBgHrLine);
        // 画第一个边框线
        mPaint.setTextSize(25);
        canvas.drawRect(startX + sidewidth + eachBoxW - 1, 0, startX + eachBoxW
                + sidewidth, sidewidth, mPaint);
        // 居中处理
        Rect textBounds = new Rect();
        mPaint.getTextBounds(weekdays[0], 0, weekdays[0].length(), textBounds);
        int textHeight = textBounds.bottom - textBounds.top;
        int textWidth = textBounds.right - textBounds.left;
        // 画第一个文字
        canvas.drawText(weekdays[0], startX + sidewidth + eachBoxW / 2
                - textWidth / 2, sidewidth / 2 + textHeight / 2, mPaint);
        for (int i = 2; i < dayTotal + 1; i++) {
            // 画边框线
            canvas.drawRect(startX + sidewidth + eachBoxW * i - 1, 0, startX
                    + eachBoxW * i + sidewidth, sidewidth, mPaint);
            // 画文字
            canvas.drawText(weekdays[i - 1], startX + sidewidth + eachBoxW
                    * (i - 1) + eachBoxW / 2 - textWidth / 2, sidewidth / 2
                    + textHeight / 2, mPaint);
        }
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            focusX = (int) event.getX();
            focusY = (int) event.getY();
            isMove = false;
        } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
            int dx = (int) (event.getX() - focusX);
            int dy = (int) (event.getY() - focusY);
            if (!isMove && Math.abs(dx) < 5 && Math.abs(dy) < 5) {
                isMove = false;
                return false;
            }
            isMove = true;
            //判断是否超出左右边框
            if (startX + dx < 0
                    && startX + dx + eachBoxW * dayTotal + sidewidth >= getWidth()) {
                startX += dx;
            }
            //判断是否超出上下边框
            if (startY + dy < 0
                    && startY + dy + eachBoxH * timeTotal + sidewidth >= getHeight()) {
                startY += dy;
            }
            //重新获得焦点坐标
            focusX = (int) event.getX();
            focusY = (int) event.getY();
            //重绘
            invalidate();
        } else if (event.getAction() == MotionEvent.ACTION_UP) {
            if (!isMove) {
                int focusX = (int) event.getX();
                int focusY = (int) event.getY();
                // 是点击效果,遍历是哪个课程的点击效果
                for (int i = 0; i < timeChoosens.size(); i++) {
                    TimerChoosen classInfo = timeChoosens.get(i);
                    if (focusX > classInfo.getFromX()
                            && focusX < classInfo.getToX()
                            && focusY > classInfo.getFromY()
                            && focusY < classInfo.getToY()) {
                        if (onItemClassClickListener != null) {
                            onItemClassClickListener.onClick(classInfo);
                             // 重绘
                            invalidate();
                        }
                        break;
                    }
                }
            }
        }
        return true;
    }

    public interface OnItemTimeClickListener {

        public void onClick(TimerChoosen timerChoosen);
    }

    public OnItemTimeClickListener getOnItemClassClickListener() {
        return onItemClassClickListener;
    }

    public void setOnItemClassClickListener(
            OnItemTimeClickListener onItemClassClickListener) {
        this.onItemClassClickListener = onItemClassClickListener;
    }

    public List<TimerChoosen> getTimerChoosens() {
        return timeChoosens;
    }

    public void setTimerChoosens(List<TimerChoosen> timerChoosens) {
        this.timeChoosens = timerChoosens;
        invalidate();// 刷新页面
    }

}
代码中的注释很清楚,想说明的一点是:在设置点击事件的时候,处理相应的点击事件很重要。我们常见的OnClickListener的设置和自定义View的实现大体一致,所有的对自定义View触摸相关操作,都要放在onTouch()中实现。

最后我们来看是如何用在Activity中的,布局文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />
    <!--<com.yxw.schedule.ScheduleView
        android:id="@+id/scheduleView"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        />-->
    <cn.sdut.lsy.time.chooser.ScheduleViewTime
        android:id="@+id/svt"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>
Activity:

package com.yxw.schedule;

import java.util.ArrayList;

import com.yxw.schedule.ScheduleView.OnItemClassClickListener;

import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.widget.Toast;

import cn.sdut.lsy.time.chooser.ScheduleViewTime;
import cn.sdut.lsy.time.chooser.TimerChoosen;

public class MainActivity extends Activity {
    private ScheduleViewTime svt;

    private ArrayList<TimerChoosen> timeChoosens;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
       
        svt = (ScheduleViewTime) findViewById(R.id.svt);
        getTimeData();
        svt.setTimerChoosens(timeChoosens);

        svt.setOnItemClassClickListener(new ScheduleViewTime.OnItemTimeClickListener() {
            @Override
            public void onClick(TimerChoosen timerChoosen) {
                Toast.makeText(MainActivity.this,
                        "您选择的时间为:" + timerChoosen.getTimeFree(),
                        Toast.LENGTH_SHORT).show();
                if(timerChoosen.isChoosen()) {
                    timerChoosen.setTimeFree("free");
                    timerChoosen.setIsChoosen(false);
                } else {
                    timerChoosen.setTimeFree("busy");
                    timerChoosen.setIsChoosen(true);
                }

            }
        });
    }

    private void getTimeData() {
        timeChoosens = new ArrayList<TimerChoosen>();
        TimerChoosen classInfo = null;
        for(int i = 1; i < 8; i++) {
            for(int j = 1; j < 4; j++) {
                Log.d("TAG","i = "+i+"::::j="+j);
                classInfo = new TimerChoosen();
                classInfo.setTimeId(i);
                classInfo.setTimeFree("free");
                classInfo.setFromTimeNum(j);
                classInfo.setWeekday(i);
                timeChoosens.add(classInfo);
                classInfo = null;
            }
        }
       
    }

}
这样就完成了我们的需求了。

代码下载:http://download.csdn.net/detail/u010665691/9062903

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值