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

来源:互联网 发布:固结快剪试验数据 编辑:程序博客网 时间:2024/05/29 06:44

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

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对象操作,然后在合适的地方刷新页面就行了;还有疑问的小伙伴可以私信我

原创粉丝点击