最近工作的需求上面需要一个日历控件,之前也在网上找了不少开源的日历控件,但是效果总是不尽人意,也许也是自己水平有限,有些代码确实太过繁琐还看不周全,没办法,只好自己动手来写了。


先简单上一张效果图




实现的很简单,只能选择起始时间和结束时间,并且加了一些简单的验证。

首先是布局文件:

picker_layout.xml布局,展示每个月份的GridView


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/back_color"
    android:orientation="vertical">

    <TextView
        android:id="@+id/date_txt"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:gravity="center"
        android:text="2016年4月"
        android:textColor="@color/white" />

    <com.newtimer.app.MyGridView
        android:id="@+id/picker_grid"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

接着是对应每一天的item picker_item.xml:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <TextView
        android:id="@+id/picker_txt"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:gravity="center"
        android:text="" />

</LinearLayout>


最后一个是主布局文件了 activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<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"
    android:background="@color/back_color"
    tools:context="com.newtimer.app.MainActivity">

    <TextView
        android:id="@+id/txt1"
        android:layout_width="150dp"
        android:layout_height="50dp"
        android:layout_alignParentLeft="true"
        android:background="@color/back_color"
        android:gravity="center"
        android:text="入住时间"
        android:textColor="@color/hotel_name_txt_color" />

    <Button
        android:id="@+id/btn_reset"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_centerHorizontal="true"
        android:background="@color/back_color"
        android:gravity="center"
        android:text="重置"
        android:textColor="@color/hotel_name_txt_color" />


    <TextView
        android:id="@+id/txt2"
        android:layout_width="150dp"
        android:layout_height="50dp"
        android:layout_alignParentRight="true"
        android:gravity="center"
        android:text="离店时间"
        android:textColor="@color/hotel_name_txt_color" />

    <LinearLayout
        android:id="@+id/week_linear"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_below="@id/txt1"
        android:layout_marginBottom="20dp"
        android:layout_marginTop="20dp"
        android:background="@color/hotel_banner_color"
        android:elevation="20dp"
        android:gravity="center"
        android:orientation="horizontal">

        <TextView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_weight="1"
            android:gravity="center"
            android:paddingRight="10dp"
            android:text="日"
            android:textColor="@color/hotel_intro_txt_color" />

        <TextView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_weight="1"
            android:gravity="center"
            android:paddingRight="10dp"
            android:text="一"
            android:textColor="@color/white" />

        <TextView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_weight="1"
            android:gravity="center"
            android:paddingRight="10dp"
            android:text="二"
            android:textColor="@color/white" />

        <TextView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_weight="1"
            android:gravity="center"
            android:paddingRight="10dp"
            android:text="三"
            android:textColor="@color/white" />

        <TextView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_weight="1"
            android:gravity="center"
            android:paddingRight="10dp"
            android:text="四"
            android:textColor="@color/white" />

        <TextView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_weight="1"
            android:gravity="center"
            android:paddingRight="10dp"
            android:text="五"
            android:textColor="@color/white" />

        <TextView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_weight="1"
            android:gravity="center"
            android:paddingRight="10dp"
            android:text="六"
            android:textColor="@color/hotel_intro_txt_color" />
    </LinearLayout>

    <ListView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/week_linear"
        android:divider="@color/transparent"
        android:scrollbars="none">

    </ListView>

</RelativeLayout>

接下来核心Java类如下:

首先是控件类:

MyGridView.java

public class MyGridView extends GridView {
    public MyGridView(Context context) {
        super(context);
    }

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

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
                MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, expandSpec);
    }
}

该类主要做了一个测量高度的工作。


接下来是控件类PickerLinear.java ,这个类主要做的就是展示每个月份的时间了,代码如下:


public class PickerLinear extends LinearLayout {
    View view;
    MyGridView myGridView;
    List<String> dateList;
    Calendar calendar;
    MyPickerAdapter myPickerAdapter;
    TextView dateTxt;
    Context mContext;
    private int month;
    private GetDateStrInterface myInterface;

    public PickerLinear(Context context, int month) {
        super(context);
        mContext = context;
        this.month = month;
        view = LayoutInflater.from(context).inflate(R.layout.picker_layout, this, true);
        initView();
        init();
        setListener();
        setAdapter();
    }

    public void setInterface(GetDateStrInterface interfaceParams) {
        this.myInterface = interfaceParams;
    }

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

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

    private void initView() {
        myGridView = (MyGridView) view.findViewById(R.id.picker_grid);
        myGridView.setNumColumns(7);
        dateTxt = (TextView) view.findViewById(R.id.date_txt);
    }

    private void init() {

        dateList = new ArrayList<>();
        calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR);

        if (month > 12) {
            int someYear = month / 12;
            year += someYear;
            month = month - 12 * someYear;
            if (month == 0) {
                month = 12;
                year -= 1;
            }
        }

        int day = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, month - 1);


        int taday = calendar.get(Calendar.DAY_OF_WEEK);
        //如果不是每月第一天,则追加空白天数
        if (taday != 1) {
            for (int i = 0; i < taday - 1; i++) {
                dateList.add(" , ");
            }
        }
        for (int i = 1; i <= day; i++) {
            dateList.add(year + "-" + month + "-" + i + "," + i);
        }
        myPickerAdapter = new MyPickerAdapter(mContext);
        myPickerAdapter.setData(dateList);
        dateTxt.setText(year + "年" + month + "月");
    }


    public void setListener() {
        myGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                try {
                    String str = (String) adapterView.getItemAtPosition(i);
                    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
                    Date date = format.parse(str);
                    Calendar c = Calendar.getInstance();
                    String str_1 = str.split(",")[0];
                    String currentStr = c.get(Calendar.YEAR) + "-" + (c.get(Calendar.MONTH) + 1) + "-" + c.get(Calendar.DAY_OF_MONTH);
                    Date currentDate = format.parse(currentStr);
                    if (date.getTime() >= currentDate.getTime() || currentStr.equals(str_1)) {  //判断只有今天之后包括今天的日期才可以点
                        if (((MainActivity) mContext).frist == null) {
                            ((MainActivity) mContext).frist = (TextView) view.findViewById(R.id.picker_txt);
                            ((MainActivity) mContext).frist.setBackgroundColor(getResources().getColor(R.color.hotel_intro_txt_color));
                            TextView tx = ((MainActivity) mContext).frist;
                            tx.setTextColor(getResources().getColor(R.color.white));
                            if (currentStr.equals(str_1)) {
                                tx.setText(tx.getText().toString().substring(0, tx.getText().toString().indexOf("\n")) + "\n入住");
                            } else {
                                tx.setText(tx.getText().toString() + "\n入住");
                            }
                            myInterface.getPreTime(str);
                        } else if (((MainActivity) mContext).last == null && ((MainActivity) mContext).frist != null && !str_1.trim().equals(((MainActivity) mContext).frist.getText().toString().trim())) {
                            String txTag = ((MainActivity) mContext).frist.getTag().toString();
                            Date fristDate = format.parse(txTag);
                            if (fristDate.getTime() < date.getTime()) {
                                ((MainActivity) mContext).last = (TextView) view.findViewById(R.id.picker_txt);
                                TextView tx = ((MainActivity) mContext).last;
                                tx.setText(tx.getText().toString() + "\n结束");
                                tx.setTextColor(getResources().getColor(R.color.white));
                                ((MainActivity) mContext).last.setBackgroundColor(getResources().getColor(R.color.hotel_intro_txt_color));
                                myInterface.getNextTime(str);
                            } else {
                                Toast.makeText(mContext, "不能选择之前的时间", Toast.LENGTH_SHORT).show();
                            }
                        }
                    } else {
//                        Toast.makeText(mContext, "不能选择过去的时间", Toast.LENGTH_SHORT).show();
                        //这个提示没什么卵用...只要不傻都知道
                    }
                } catch (ParseException exception) {
                    Toast.makeText(mContext, "报错了" + exception.getMessage(), Toast.LENGTH_SHORT).show();
                }
            }
        });
    }

    public void setAdapter() {
        myGridView.setAdapter(myPickerAdapter);
    }


    interface GetDateStrInterface { //回调接口,让前边儿页面可以获取到时间
        void getPreTime(String preStr);

        void getNextTime(String nextStr);
    }
}


接下来是 MyPickerAdapter.java ,这个文件的作用是给显示每个月份的GridView绑定数据。


public class MyPickerAdapter extends BaseAdapter {
    private List<String> dateList;
    private Context mContext;

    public MyPickerAdapter(Context context) {
        this.mContext = context;
    }

    public void setData(List<String> data) {
        this.dateList = data;
    }

    @Override
    public int getCount() {
        if (dateList != null && dateList.size() > 0) {
            return dateList.size();
        }
        return 0;
    }

    @Override
    public Object getItem(int i) {
        return dateList.get(i);
    }

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

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        ViewHolder vh;
        if (view == null) {
            vh = new ViewHolder();
            view = LayoutInflater.from(mContext).inflate(R.layout.picker_item, null, false);
            vh.tx = (TextView) view.findViewById(R.id.picker_txt);
            view.setTag(vh);
        } else {
            vh = (ViewHolder) view.getTag();
        }
        String[] strArr = dateList.get(i).toString().split(",");
        Calendar calendar = Calendar.getInstance();
        int month = calendar.get(Calendar.MONTH) + 1;
        if (strArr[0].equals(" ") || strArr[0].equals("")) {
            vh.tx.setText(strArr[0]);
        } else {
            String currentStr = calendar.get(Calendar.YEAR) + "-" + (calendar.get(Calendar.MONTH) + 1) + "-" + calendar.get(Calendar.DAY_OF_MONTH);
            Date currentDate = getDate(currentStr);
            Date date = getDate(strArr[0]);
            String s = strArr[0].split("-")[1];
            int now_month = Integer.parseInt(s);
            int day = Integer.parseInt(strArr[1].trim());
            if (date.getTime() < currentDate.getTime()) {
                vh.tx.setTextColor(mContext.getResources().getColor(R.color.hotel_name_txt_color));
            } else {
                if ((i + 1) % 7 == 1) {  //计算为周日时显示的颜色
                    vh.tx.setTextColor(mContext.getResources().getColor(R.color.hotel_intro_txt_color));
                } else if ((i + 1) % 7 == 0) {//计算为周六时显示的颜色
                    vh.tx.setTextColor(mContext.getResources().getColor(R.color.hotel_intro_txt_color));
                } else {
                    vh.tx.setTextColor(mContext.getResources().getColor(R.color.white));
                }
            }
            StringBuffer dateValue = new StringBuffer();
            dateValue.append(strArr[1]);
            if (day == calendar.get(Calendar.DAY_OF_MONTH) && month == now_month) {
                dateValue.append("\n今天");
            }
            vh.tx.setText(dateValue);
            vh.tx.setTag(strArr[0]);

        }
        return view;
    }

    class ViewHolder {
        TextView tx;
    }

    public Date getDate(String currentStr) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Date currentDate = null;
        try {
            currentDate = format.parse(currentStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return currentDate;
    }
}

使用方法的MainActivity.java代码如下:

public class MainActivity extends AppCompatActivity implements PickerLinear.GetDateStrInterface {

    PickerLinear pickerLinear;
    Calendar calendar;
    ListView list_view;
    List<PickerLinear> pickerLinears;
    TextView tx1, tx2;
    Button btn_reset;
    public TextView frist;
    public TextView last;
    private ListAdapter listAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        list_view = (ListView) findViewById(R.id.list_view);
        tx1 = (TextView) findViewById(R.id.txt1);
        tx2 = (TextView) findViewById(R.id.txt2);
        btn_reset = (Button) findViewById(R.id.btn_reset);
        init();
        setListener();
    }

    private void init() {
        pickerLinears = new ArrayList<>();
        calendar = Calendar.getInstance();
        int month = calendar.get(Calendar.MONTH) + 1;
        for (int i = 0; i < 6; i++) {
            pickerLinear = new PickerLinear(this, month + i);
            pickerLinear.setInterface(this);
            pickerLinears.add(pickerLinear);
        }
        listAdapter = new ListAdapter();
        list_view.setAdapter(listAdapter);
    }

    private void setListener() {
        btn_reset.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (frist != null) {
                    String fristStr = frist.getText().toString().substring(0, frist.getText().toString().indexOf("\n")).trim();
                    int fristDate = Integer.parseInt(fristStr);
                    if (fristDate % 7 == 1) {
                        frist.setTextColor(getResources().getColor(R.color.hotel_intro_txt_color));
                    } else if (fristDate % 7 == 0) {
                        frist.setTextColor(getResources().getColor(R.color.hotel_intro_txt_color));
                    } else {
                        frist.setTextColor(getResources().getColor(R.color.hotel_name_txt_color));
                    }
                    frist.setBackgroundColor(getResources().getColor(R.color.back_color));
                    if (fristStr.equals(calendar.get(Calendar.DAY_OF_MONTH) + "")) {
                        frist.setText(fristStr + "\n今天");
                    } else {
                        frist.setText(fristStr);
                    }
                }
                if (last != null) {
                    String lastStr = last.getText().toString().substring(0, last.getText().toString().indexOf("\n")).trim();
                    int lastDate = Integer.parseInt(lastStr);
                    if (lastDate % 7 == 1) {
                        last.setTextColor(getResources().getColor(R.color.hotel_intro_txt_color));
                    } else if (lastDate % 7 == 0) {
                        last.setTextColor(getResources().getColor(R.color.hotel_intro_txt_color));
                    } else {
                        last.setTextColor(getResources().getColor(R.color.hotel_name_txt_color));
                    }
                    last.setBackgroundColor(getResources().getColor(R.color.back_color));
                    last.setText(lastStr);
                }
                frist = null;
                last = null;
                tx1.setText("入住时间");
                tx2.setText("离店时间");
                listAdapter.notifyDataSetChanged();
            }
        });
    }

    @Override
    public void getPreTime(String preStr) {
        String date = preStr.split(",")[0];
        String[] dateArr = date.split("-");
        tx1.setText("入住时间\n" + dateArr[0] + "年" + dateArr[1] + "月" + dateArr[2] + "日");
    }

    @Override
    public void getNextTime(String nextStr) {
        String date = nextStr.split(",")[0];
        String[] dateArr = date.split("-");
        tx2.setText("离店时间\n" + dateArr[0] + "年" + dateArr[1] + "月" + dateArr[2] + "日");
    }


    class ListAdapter extends BaseAdapter {

        @Override
        public int getCount() {
            return pickerLinears.size();
        }

        @Override
        public Object getItem(int i) {
            return pickerLinears.get(i);
        }

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

        @Override
        public View getView(int i, View view, ViewGroup viewGroup) {

            return pickerLinears.get(i);
        }
    }

}


以上就是所有源代码了,算是一个基础的demo,希望能帮助到新手,如果有更好意见和建议欢迎交流,共同学习。

代码地址: https://github.com/color9169/customCalendar










Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐