1. 程式人生 > >Android 自定義自由選擇時間區間的日曆控制元件

Android 自定義自由選擇時間區間的日曆控制元件

摸滾打爬在Android界小菜鳥,突然靜下心想想自己都做過些什麼呢!留下些什麼呢!感覺自己老是copy別人的東西自己都不好意思了,於是今天就 來分享下自己最近寫專案中的一個自定義日曆控制元件 (翻閱了各大開源日曆都沒有合適的),希望大家多多指點,第一次寫部落格如果有不足之處,請儘管噴。

  

因為自己不知道怎麼描述那我就直接上程式碼了。


因為這個是自己寫的demo adapter等沒有分開寫, 自己分開寫Adapter,如果你覺得對你有用可以自己,放在不同的資料夾下面。

public class MainActivity extends AppCompatActivity {

    private ListView mListView;
    private CalendarListAdapter mAdapter;

    private List<CalendarModel> calendarModels;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        calendarModels = getData();

        mListView = (ListView) findViewById(R.id.listview);

        mAdapter = new CalendarListAdapter(this);
        mListView.setAdapter(mAdapter);

        mAdapter.setDataSource(calendarModels);
        mAdapter.notifyDataSetChanged();
    }

    private int lastPosition = 0;

    private List<CalendarModel> getData() {
        List<CalendarModel> calendarModels = new ArrayList<CalendarModel>();
        int year = 2017;

        for (int index = 0; index < 12; index++) {
            CalendarModel calendarModel = new CalendarModel();
            calendarModel.setMonthIndex(index);
            calendarModel.setMonthDays(getDaysInMonth(index, year));
            if (index == 0) {
                calendarModel.setFirstPosition(6);
                calendarModel.setLastPosition(1);
                lastPosition = 1;
            } else {
                calendarModel.setFirstPosition(lastPosition + 1);
                lastPosition = (getDaysInMonth(index, year) + lastPosition) % 7;
                calendarModel.setLastPosition(lastPosition);

            }

            calendarModels.add(calendarModel);
        }

        return calendarModels;
    }

    private int getDaysInMonth(int month, int year) {
        switch (month) {
            case Calendar.JANUARY:
            case Calendar.MARCH:
            case Calendar.MAY:
            case Calendar.JULY:
            case Calendar.AUGUST:
            case Calendar.OCTOBER:
            case Calendar.DECEMBER:
                return 31;
            case Calendar.APRIL:
            case Calendar.JUNE:
            case Calendar.SEPTEMBER:
            case Calendar.NOVEMBER:
                return 30;
            case Calendar.FEBRUARY:
                return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) ? 29 : 28;
            default:
                throw new IllegalArgumentException("Invalid Month");
        }
    }

    class CalendarListAdapter extends BaseAdapter {

        private Context mContext;
        private List<CalendarModel> dataSource;

        public void setDataSource(List<CalendarModel> dataSource) {
            this.dataSource = dataSource;
        }

        public CalendarListAdapter(Context context) {
            mContext = context;
        }

        @Override
        public int getCount() {
            return dataSource == null ? 0 : dataSource.size();
        }

        @Override
        public CalendarModel getItem(int i) {
            return dataSource == null ? null : dataSource.get(i);
        }

        @Override
        public long getItemId(int i) {
            return i;
        }

        @Override
        public View getView(int i, View view, ViewGroup viewGroup) {
            ViewHolder viewHolder;
            if (view == null) {
                viewHolder = new ViewHolder();
                view = LayoutInflater.from(mContext).inflate(R.layout.item_list_calendar, null);
                viewHolder.titleView = (TextView) view.findViewById(R.id.title_tv);
                viewHolder.gridView = (CustomGridView) view.findViewById(R.id.days_grid);
                view.setTag(viewHolder);
            } else {
                viewHolder = (ViewHolder) view.getTag();
            }

            CalendarModel calendarModel = getItem(i);
            if (calendarModel != null) {
                viewHolder.titleView.setText(String.valueOf(calendarModel.getMonthIndex() + 1));

                int first = calendarModel.getFirstPosition();
                int last = calendarModel.getLastPosition();

                CalendarGridAdapter adapter = new CalendarGridAdapter(mContext,calendarModel.getMonthIndex() + 1);
                viewHolder.gridView.setAdapter(adapter);

                List<DayModel> dataSource = new ArrayList<DayModel>();
                for (int index = 0; index < first; index++) {
                    DayModel dayModel = new DayModel();
                    dayModel.setDayIndex(0);
                    dayModel.setMonthIndex(calendarModel.getMonthIndex() + 1);
                    dataSource.add(dayModel);
                }

                int days = calendarModel.getMonthDays();
                for (int index = 0; index < days; index++) {
                    DayModel dayModel = new DayModel();
                    dayModel.setDayIndex(index + 1);
                    dataSource.add(dayModel);
                }

                adapter.setDataSource(dataSource);
                adapter.notifyDataSetChanged();
            }

            return view;
        }

        class ViewHolder {
            TextView titleView;
            CustomGridView gridView;
        }
    }

    private List<MonthDayModel> monthDayModels = new ArrayList<MonthDayModel>();

    class CalendarGridAdapter extends BaseAdapter {
        int curentMonth;
        private Context mContext;
        private List<DayModel> dataSource;



        List<HashMap<String,Long>>  limitTime = new ArrayList<HashMap<String,Long>>();

        public void setDataSource(List<DayModel> dataSource) {
            this.dataSource = dataSource;
        }

        public CalendarGridAdapter(Context context,int curentMonth) {
            mContext = context;
            this.curentMonth = curentMonth;
            //模擬後臺指定的開始時間和結束時間
            HashMap<String,Long> map1 = new HashMap<>();
            map1.put("startTime",1490716800000L);
            map1.put("endTime",1491580799000L);
            limitTime.add(map1);

            HashMap<String,Long> map2 = new HashMap<>();
            map2.put("startTime",1491926800000L);
            map2.put("endTime",1492444799000L);
            limitTime.add(map2);

        }

        @Override
        public int getCount() {
            return dataSource == null ? 0 : dataSource.size();
        }

        @Override
        public DayModel getItem(int i) {
            return dataSource == null ? null : dataSource.get(i);
        }

        @Override
        public long getItemId(int i) {
            return i;
        }

        @Override
        public View getView(int i, View view, ViewGroup viewGroup) {
            final ViewHolder viewHolder;
            if (view == null) {
                viewHolder = new ViewHolder();
                view = LayoutInflater.from(mContext).inflate(R.layout.item_grid_calendar, null);
                viewHolder.titleView = (TextView) view.findViewById(R.id.day_tv);
                view.setTag(viewHolder);
            } else {
                viewHolder = (ViewHolder) view.getTag();
            }
            final View state_line = view.findViewById(R.id.state_line);
            final DayModel dayModel = getItem(i);
            if (dayModel != null && dayModel.getDayIndex() != 0) {
                viewHolder.titleView.setText(String.valueOf(dayModel.getDayIndex()));
                viewHolder.titleView.setVisibility(View.VISIBLE);
            } else {
                viewHolder.titleView.setVisibility(View.INVISIBLE);
            }

            int month = dayModel.getMonthIndex();
            final int day = dayModel.getDayIndex();

            int size = monthDayModels.size();
            for (int index = 0; index < size; index++) {
                MonthDayModel monthDayModel =  monthDayModels.get(index);
                if (monthDayModel != null) {
                    if (monthDayModel.getDay() == day && monthDayModel.getMonth() == month) {
                        viewHolder.titleView.setTextColor(Color.parseColor("#FF0000"));
                    } else {
                        viewHolder.titleView.setTextColor(Color.parseColor("#999999"));
                    }
                } else {
                    viewHolder.titleView.setTextColor(Color.parseColor("#999999"));
                }
            }
            String dateStr = "2017-"+curentMonth+"-"+day+" 00:00:00";
//            Log.e("date",dateStr);
            final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            try {
                Date date = simpleDateFormat.parse(dateStr);
                final long timeSecond = date.getTime();
                boolean isContain = isContaingDate(timeSecond);
                if(isContain){
                    viewHolder.titleView.setTextColor(Color.parseColor("#FF0000"));
//                    state_line.setVisibility(View.VISIBLE);
                }else{
                    viewHolder.titleView.setTextColor(Color.parseColor("#999999"));
//                    state_line.setVisibility(View.GONE);
                }
                if(checkStartTime != 0 && checkEndTime != 0){
                    //選擇了開始時間和結束時間,並且顯示區間的下劃線
                    if(timeSecond >= checkStartTime && timeSecond <= checkEndTime){
                        state_line.setVisibility(View.VISIBLE);
                    }
                }else{
                    //當天的最後時刻
                    String todayEnd = "2017-"+curentMonth+"-"+day+" 23:59:59";
                    //獲取當天最後時刻的好描述
                    long todaySecondEnd = simpleDateFormat.parse(todayEnd).getTime();
                    //如果選擇的開始時間大於當天凌晨0點0分0秒 並且小於當天時間23點59分59秒的時候
                    //也就是說,只選擇了一個開始時間  並且這個開始時間在當天的範圍之內 就顯示下劃線
                    if(checkStartTime >= timeSecond && checkStartTime <= todaySecondEnd){
                        state_line.setVisibility(View.VISIBLE);
                    }else{
                        state_line.setVisibility(View.GONE);
                    }
                }

                viewHolder.titleView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        boolean isContain = isContaingDate(timeSecond);
                        if(!isContain){
                            //在伺服器的區間內,才能點選
                            Toast.makeText(mContext,"所選日期不在要求範圍內!",Toast.LENGTH_SHORT).show();
                            return;
                        }
                        if(checkStartTime == 0 && checkEndTime == 0){
                            //開始時間和結束時間均為空,則先選擇開始時間
                            String dateStr = "2017-"+curentMonth+"-"+day+" 00:00:00";
                            try {
                                Date date  = simpleDateFormat.parse(dateStr);
                                checkStartTime = date.getTime();
                                notifyDataSetChanged();
                            } catch (ParseException e) {
                                e.printStackTrace();
                            }
                        }else if(checkEndTime == 0 && checkStartTime != 0){
                            //開始時間不為空,且結束時間為空
                            String dateStr = "2017-"+curentMonth+"-"+day+" 23:59:59";
                            try {
                                Date date  = simpleDateFormat.parse(dateStr);
                                long checkTime = date.getTime();
                                if(checkTime <= checkStartTime){
                                    Toast.makeText(mContext,"結束時間應該大於開始時間!",Toast.LENGTH_SHORT).show();
                                    return;
                                }else{
                                    boolean issameSpace = isInSameSpace(checkStartTime,checkTime);
                                    if(issameSpace){
                                        checkEndTime = checkTime;
                                    }else{
                                        Toast.makeText(mContext,"開始時間和結束時間不在同一個可選區間內!",Toast.LENGTH_SHORT).show();
                                        return;
                                    }
                                }
                                notifyDataSetChanged();
                            } catch (ParseException e) {
                                e.printStackTrace();
                            }
                        }else{
                            //當開始時間不為空且結束時間也不為空,這個時候,就設定開始時間為當前時間,結束時間為0
                            String dateStr = "2017-"+curentMonth+"-"+day+" 00:00:00";
                            try {
                                Date date  = simpleDateFormat.parse(dateStr);
                                checkStartTime = date.getTime();
                                checkEndTime = 0;
                                notifyDataSetChanged();
                            } catch (ParseException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                });
            } catch (ParseException e) {
                e.printStackTrace();
            }
            return view;
        }


        /**
         * 所選的開始時間和結束時間是否在同一個區間內
         * @param startTime
         * @param endTime
         * @return
         */
        boolean isInSameSpace(long startTime,long endTime){
            for(HashMap<String,Long> map:limitTime){
                long timeStart = map.get("startTime");
                long timeEnd = map.get("endTime");
                if(startTime >= timeStart && startTime <= timeEnd
                        && endTime >= timeStart && endTime <= timeEnd){
                    return true;
                }
            }
            return false;
        }

        long checkStartTime = 0,checkEndTime = 0;


        private boolean isContaingDate(long timeSecond) {
            for(HashMap<String,Long> map:limitTime){
                long timeStart = map.get("startTime");
                long timeEnd = map.get("endTime");
                if(timeSecond >= timeStart && timeSecond <= timeEnd){
                    return true;
                }
            }
            return false;
        }


        class ViewHolder {
            TextView titleView;
        }
    }

}

後期我會把程式碼整理好開源給小夥伴們......

Demo地址:http://download.csdn.net/detail/bimromatic/9837950