自定义日历,随心所欲的打造自己的日历选择器

不多说,先上图,第一次录屏,剪切的有点烂,将就看

title显示日期和星期,下面三个滚动控件,还有三个圆圈指示


正文开始

1.先看布局图
清楚明了

我们可以清晰的看到视图的结构

    1.头部两个TextView,左边是日期,右边是星期
    2.下方三个ListView ,每个ListView中间有个选择指示的圆

下面是xml的布局代码 , 不想看代码的可以略过

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:background="@color/black"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:layout_margin="30dp"
        android:background="@drawable/shape_all_round"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <LinearLayout
            android:layout_marginTop="15dp"
            android:layout_gravity="center_horizontal"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">

            <TextView
                android:id="@+id/show_title_year_month_day"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
            <TextView
                android:id="@+id/show_title_week"
                android:layout_marginLeft="20dp"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />

        </LinearLayout>

        <LinearLayout
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="200dp">
            <RelativeLayout
                android:layout_margin="10dp"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="match_parent">

                <ListView
                    android:id="@+id/list_view_year"
                    android:divider="@null"
                    android:scrollbars="none"
                    android:listSelector="@color/color_null"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"/>
                <TextView
                    android:background="@drawable/shap_calendar_list_btm_plastic"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent" />

                <ImageView
                    app:srcCompat="@drawable/ic_round"
                    android:layout_centerInParent="true"
                    android:layout_width="80dp"
                    android:layout_height="80dp" />
            </RelativeLayout>
            <RelativeLayout
                android:layout_margin="10dp"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="match_parent">

                <ListView
                    android:id="@+id/list_view_month"
                    android:divider="@null"
                    android:scrollbars="none"
                    android:listSelector="@color/color_null"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"/>

                <TextView
                    android:background="@drawable/shap_calendar_list_btm_plastic"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent" />

                <ImageView
                    app:srcCompat="@drawable/ic_round"
                    android:layout_centerInParent="true"
                    android:layout_width="80dp"
                    android:layout_height="80dp" />

            </RelativeLayout>
            <RelativeLayout
                android:layout_margin="10dp"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="match_parent">

                <ListView
                    android:id="@+id/list_view_day"
                    android:divider="@null"
                    android:scrollbars="none"
                    android:listSelector="@color/color_null"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"/>
                <TextView
                    android:background="@drawable/shap_calendar_list_btm_plastic"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent" />
                <ImageView
                    app:srcCompat="@drawable/ic_round"
                    android:layout_centerInParent="true"
                    android:layout_width="80dp"
                    android:layout_height="80dp" />

            </RelativeLayout>
        </LinearLayout>

    </LinearLayout>

</LinearLayout>

上面的圆形图片用的是svg格式的矢量图,不会用svg的小伙伴,可以将图片替换为png的图片,把app:srcCompat 改成 android:src就行了
shap_calendar_list_btm_plastic.xml 这就是做一个毛玻璃的效果,从上下开始到中间,透明度逐渐变高,就能显示出类似滚轮的效果来,下面贴出代码,顺便把color的代码一起贴出来


布局文件的背景

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="@color/white"/>
    <corners android:radius="15dp"/>
</shape>

这是shap_calendar_list_btm_plastic.xml的

<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <gradient
        android:angle="90"
        android:startColor="@color/white_btm_f"
        android:centerColor="@color/white_btm_0"
        android:endColor="@color/white_btm_f"/>

</shape>

这是color的

    <color name="white_btm_0">#00ffffff</color>
    <color name="white_btm_1">#11ffffff</color>
    <color name="white_btm_2">#22ffffff</color>
    <color name="white_btm_3">#33ffffff</color>
    <color name="white_btm_4">#44ffffff</color>
    <color name="white_btm_5">#55ffffff</color>
    <color name="white_btm_6">#66ffffff</color>
    <color name="white_btm_7">#77ffffff</color>
    <color name="white_btm_8">#88ffffff</color>
    <color name="white_btm_9">#99ffffff</color>
    <color name="white_btm_a">#aaffffff</color>
    <color name="white_btm_b">#bbffffff</color>
    <color name="white_btm_c">#ccffffff</color>
    <color name="white_btm_d">#ddffffff</color>
    <color name="white_btm_e">#eeffffff</color>
    <color name="white_btm_f">#ffffffff</color>

2.java代码部分


适配器


/**
 * 适配器
 * Created by zcy on 2017/8/2.
 */
public class CalendarListAdapter extends BaseAdapter {

    private Context mContext;
    private List<Integer> list;
    //listView中显示的item个数
    private int count;
    //最小个数,如果count比这个值小,将会默认使用MIN_COUNT
    private static final int MIN_COUNT = 3;

    public static final int TYPE_YEAR = 10;//年
    public static final int TYPE_MONTH = 11;//月
    public static final int TYPE_DAY = 12;//日

    private int type;

    public CalendarListAdapter(Context mContext, List<Integer> list , int count , int type) {
        this.mContext = mContext;
        this.list = list;
        this.count = count;
        this.type = type;
    }

    public CalendarListAdapter(Context mContext) {
        this.mContext = mContext;
    }

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

    @Override
    public Object getItem(int i) {
        return null;
    }

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

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        int height = viewGroup.getHeight();
        TextView textView = new TextView(mContext);
        textView.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
        textView.setHeight(count < MIN_COUNT ? height/MIN_COUNT : height/count);
        textView.setGravity(Gravity.CENTER);
        textView.setText(list.get(i) < 0 ? "" :new StringBuilder().append(list.get(i)).append(getTypeName()));
        return textView;
    }

    private String getTypeName(){
        String name =  null;
        switch (type){
            case TYPE_YEAR:
                name = "年";
                break;
            case TYPE_MONTH:
                name = "月";
                break;
            case TYPE_DAY:
                name = "日";
                break;
            default:
                name = "";
                break;
        }
        return name;
    }
}

实现代码


/**
 * 日历fragment
 * Created by zcy on 2017/8/2.
 */

public class CalendarFragment extends BaseFragment {

    public static CalendarFragment getInstance(){
        return new CalendarFragment();
    }

    // 年月日 , 星期几
    @BindView(R.id.show_title_year_month_day)
    TextView titleYMD;
    @BindView(R.id.show_title_week) TextView titleNeek;
    //年份选择 , 月份选择 ,天数选择
    @BindView(R.id.list_view_year)
    ListView listViewYear;
    @BindView(R.id.list_view_month) ListView listViewMonth;
    @BindView(R.id.list_view_day) ListView listViewDay;

    //年份listView中显示的第一个item编号
    private int firstVisibleYearItem;
    //月份listView中显示的第一个item编号
    private int firstVisibleMonthItem;
    //天数listView中显示的第一个item编号
    private int firstVisibleDayItem;

    private List<Integer> listYear;
    private List<Integer> listMonth;
    private List<Integer> listDay;

    //初始年份和结束年份
    private int firstYear;
    private int lastYear;




    //年月日的适配器
    private CalendarListAdapter yearAdapter;
    private CalendarListAdapter monthAdapter;
    private CalendarListAdapter daydApter;

    //日历对象
    private Calendar calendar;
    //当前时间,年,月,日,周
    private int currentTimeYear;
    private int currentTimeMonth;
    private int currentTimeDay;



    @Override
    protected int getLayoutId() {
        return R.layout.fragment_calendar;
    }

    @Override
    protected void initViews() {
        initYearListView();
        initMonthListView();
        initDayListView();
        listViewYear.setSelection(listYear.indexOf(currentTimeYear)-1);
        listViewMonth.setSelection(listMonth.indexOf(currentTimeMonth)-1);
        listViewDay.setSelection(listDay.indexOf(currentTimeDay)-1);
        upData(false);
    }

    @Override
    protected void init() {
        initYear();
        initMonth();
        calendar = Calendar.getInstance();
        currentTimeYear = calendar.get(Calendar.YEAR);
        currentTimeMonth = calendar.get(Calendar.MONTH)+1;
        currentTimeDay = calendar.get(Calendar.DAY_OF_MONTH);
        upData(false);
    }

    //初始化天数的listView
    private void initDayListView() {
        daydApter = new CalendarListAdapter(getContext() , listDay , 0 , CalendarListAdapter.TYPE_DAY);
        listViewDay.setAdapter(daydApter);
        listViewDay.setSelected(true);
        listViewDay.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView absListView, int i) {
                if (i == SCROLL_STATE_IDLE){
                    listViewDay.setSelection(firstVisibleDayItem);
                    calendar.set(Calendar.DAY_OF_MONTH ,listDay.get(firstVisibleDayItem+1));
                    upData(false);
                }
            }

            @Override
            public void onScroll(AbsListView absListView, int i, int i1, int i2) {
                firstVisibleDayItem = i;
            }
        });
    }
    //初始化月份的listView
    private void initMonthListView() {
        monthAdapter = new CalendarListAdapter(getContext() , listMonth , 0 , CalendarListAdapter.TYPE_MONTH);
        listViewMonth.setAdapter(monthAdapter);
        listViewMonth.setSelected(true);
        listViewMonth.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView absListView, int i) {
                if (i == SCROLL_STATE_IDLE){
                    listViewMonth.setSelection(firstVisibleMonthItem);
//                    upDayList();
                    calendar.set(Calendar.DAY_OF_MONTH , 1);
                    calendar.set(Calendar.MONTH , listMonth.get(firstVisibleMonthItem+1)-1);
                    upData(true);
                }
            }

            @Override
            public void onScroll(AbsListView absListView, int i, int i1, int i2) {
                firstVisibleMonthItem = i;
            }
        });

    }
    //初始化年份的listView
    private void initYearListView() {
        yearAdapter = new CalendarListAdapter(getContext() , listYear , 0 , CalendarListAdapter.TYPE_YEAR);
        listViewYear.setAdapter(yearAdapter);
        listViewYear.setSelected(true);
        listViewYear.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView absListView, int i) {
                if (i == SCROLL_STATE_IDLE){
                    listViewYear.setSelection(firstVisibleYearItem);
//                    upDayList();
                    calendar.set(Calendar.DAY_OF_MONTH , 1);
                    calendar.set(Calendar.YEAR , listYear.get(firstVisibleYearItem + 1));
                    upData(true);
                }
            }

            @Override
            public void onScroll(AbsListView absListView, int i, int i1, int i2) {
                //此处i代表屏幕中显示的第一个item
                firstVisibleYearItem = i;
            }
        });
    }


    /**
     * 有任何动作之后刷新数据和界面
     * @param isNotify 是否对天数的适配器进行刷新
     */
    private void upData(boolean isNotify){
        initDay();
        if (isNotify && null != daydApter){
            daydApter.notifyDataSetChanged();
            //这里须要在刷新之后将selection设置为0,否则在31号的时候调整月份,会出现显示异常的情况
            listViewDay.setSelection(0);
        }
        if (null != calendar){
            if (null != titleYMD)titleYMD.setText(getYMD());
            if (null != titleNeek)titleNeek.setText(getNeek());

        }
    }

    //从Calendar中取出年月日并拼接成想要的格式
    private String getYMD(){
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH);
        int day = calendar.get(Calendar.DAY_OF_MONTH);
        StringBuilder sb = new StringBuilder();
        if (year >= 1900){
            sb.append(year).append("年");
            if (month >= 0 && month <12){
                sb.append(month+1).append("月")
                        .append(day);
            }
        }
        return sb.toString();
    }
    //从Calendar中取出星期数,并返回对应的名称
    private String getNeek(){
        int dayOfNeek = calendar.get(Calendar.DAY_OF_WEEK);
        String neek = null;
        switch (dayOfNeek){
            case 1:
                neek = "星期日";
                break;
            case 2:
                neek = "星期一";
                break;
            case 3:
                neek = "星期二";
                break;
            case 4:
                neek = "星期三";
                break;
            case 5:
                neek = "星期四";
                break;
            case 6:
                neek = "星期五";
                break;
            case 7:
                neek = "星期六";
                break;
            default:
                neek = "";
                break;
        }
        return neek;
    }

    //初始化天数list数据
    private void initDay(){
        //指定年份指定月份有多少天
        int actualMaximum = calendar.getActualMaximum(Calendar.DATE);
        if (null == listDay)listDay = new ArrayList<>();
        else listDay.clear();
        listDay.add(-1);
        for (int i = 1 ; i <= actualMaximum ; i++){
            listDay.add(i);
        }
        listDay.add(-1);
    }

    //初始化年份相关
    private void initYear() {
        firstYear = 2000;
        lastYear = 2017;
        if (null == listYear) listYear = new ArrayList<>();
        else listYear.clear();
        listYear.add(-1);
        for (int i = firstYear ; i <= lastYear ; i++){
            listYear.add(i);
        }
        listYear.add(-1);
    }

    //初始化月份
    private void initMonth(){
        if (null == listMonth) listMonth = new ArrayList<>();
        else listMonth.clear();
        listMonth.add(-1);
        for (int i = 0 ; i < 12 ; i++){
            listMonth.add(i+1);
        }
        listMonth.add(-1);
    }


}

这里我将逻辑全写在Fragment里面了,哪里需要用的时候,直接加载这个fragment就行了,还有个BaseFragment,也贴个代码吧



/**
 * baseFragment
 * Created by zcy on 2017/8/2.
 */
public abstract class BaseFragment extends Fragment{

    /**
     * 这个方法提供初始化的布局id
     * @return 布局id
     */
    protected abstract int getLayoutId();
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(getLayoutId(),container,false);
        ButterKnife.bind(this,view);
        initViews();
        return view;
    }
    /**
     * 初始化视图控件,代替了onCreateView,不需要再重写onCreateView在该方法里面写具体实现就可以了
     */
    protected abstract void initViews();

    /**
     * 初始化成员属性,不需要手动调用,只需要重写内容即可
     */
    protected abstract void init();

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        init();
    }

}

有点乱,也不是很复杂,需要用到的可以自己整理一下;基本全局就对一个Calendar对象操作,然后在合适的地方刷新页面就行了;还有疑问的小伙伴可以私信我

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值