精华内容
下载资源
问答
  • Android日历签到

    2016-11-01 18:20:53
    Android日历签到
  • Android日历签到.rar,太多无法一一验证是否可用,程序如果跑不起来需要自调,部分代码功能进行参考学习。
  • 添加compile'com.prolificinteractive:material-calendarview:1.4.2'2.添加日历控件到布局中//设置周的文本calendarView.setWeekDayLabels(newString[]{"日","一","二","三","四","五","六"});//日期点击事件calen.....

    MaterialCalendarView项目开源地址:

    4fd708bf9f4f

    集成清单

    1.添加compile'com.prolificinteractive:material-calendarview:1.4.2'

    2.添加日历控件到布局中

    //设置周的文本calendarView.setWeekDayLabels(newString[]{"日","一","二","三","四","五","六"});

    //日期点击事件calendarView.setOnDateChangedListener(this);

    calendarView.setSelectedDate(CalendarDay.today());//当日选中

    //设置选中日期颜色。

    calendarView.setSelectionColor(getResources().getColor(R.color.color_fdd369));

    calendarView.setTitleFormatter(new DateFormatTitleFormatter(DateTimeFormatter.ofPattern("yyyy年MM月")));//设置当前标题日期格式

    calendarView.setSelectionMode(MaterialCalendarView.SELECTION_MODE_MULTIPLE);//默认单选模式  这里选择多选模式

    calendarView.setDateSelected(CalendarDay.from(2019, 3, 25), true);//设置当前日期为选中状态

    4fd708bf9f4f

    12sp

    @color/colorWhite

    //日历头部字体样式设置

    app:mcv_headerTextAppearance="@style/MaterialheaderTextStyelNormal"

    //日历时间字体样式设置

    app:mcv_weekDayTextAppearance="@style/MaterialCalendarTextStyelNormal"

    //设置左边 和右边箭头 图片

    app:mcv_leftArrow="@mipmap/leftgo"

    app:mcv_rightArrow="@mipmap/rightgo"

    //设置头部  标题日期动画方式 横向 还是 竖向 过度

    app:mcv_titleAnimationOrientation="horizontal"

    //设置日历时间 之间高度

    app:mcv_tileHeight="30dp"

    //日历从左到右  第一周显示的  (此处是星期天)

    app:mcv_firstDayOfWeek="sunday"

    展开全文
  • EasyCalendarQuickly customize the calendar UI. You can use EasyCalendar to quickly get the calendar style UI.FeatureCustom layout for title.Custom layout for date.Show or hide divider for date.Show or...

    EasyCalendar

    Quickly customize the calendar UI. You can use EasyCalendar to quickly get the calendar style UI.

    Feature

    Custom layout for title.

    Custom layout for date.

    Show or hide divider for date.

    Show or hide overflow date.

    Listen to date's view be clicked.

    Screenshot

    0d48f6b36a81d39ef9b7edbf377f66f3.gif9ec7e49bfb67a3b3836254f3a3e97abe.png

    21b0ca35b0b0a6212e228aea271e8d7a.gifscreenshot_checkin.jpg

    Gradle

    compile 'com.sch.calendar:easy-calendar:1.0.1'

    Attributes

    name

    format

    description

    titleColor

    color

    set color for title

    titleLayout

    reference

    custom layout for title

    weekColor

    color

    set color for week

    weekBackground

    color|reference

    set background for week bar

    monthBackground

    color|reference

    set backgroung for month layout

    dateDividerColor

    color

    set color for divider of date

    dateDividerSize

    dimension

    set size for divider of date

    imgLastMonth

    reference

    set image for button of last month

    imgNextMonth

    reference

    set image for button of next month

    language

    enum

    china: 中文, english: English

    API

    Show or hide overflow date.

    /**

    * If true, show whole calendar.

    * e.g. showing date is April, if show whole calendar, 03/30 and 05/01 will show.

    */

    public void setShowOverflowDate(boolean showOverflowDate);

    public boolean isShowOverflowDate();

    Set format for title.

    /**

    * Constructs a SimpleDateFormat using the given pattern and

    * the default date format symbols for the given locale.

    * Note: This constructor may not support all locales.

    * For full coverage, use the factory methods in the {@link DateFormat}

    * class.

    *

    * @param pattern the pattern describing the date and time format

    * @param locale the locale whose date format symbols should be used

    */

    public void setTitleFormat(String pattern, Locale locale);

    Set a listener for callback when date was clicked.

    /**

    * Set listener for date be clicked.

    *

    * @param onDateClickedListener listener

    */

    public void setOnDateClickedListener(OnDateClickedListener onDateClickedListener);

    Set a listener for callback when showing month changed.

    /**

    * Set listener for current showing month changed.

    *

    * @param onMonthChangedListener listener

    */

    public void setOnMonthChangedListener(final OnMonthChangedListener onMonthChangedListener);

    Set can or can't change month by drag.

    /**

    * Set drag enable for page.

    */

    public void setCanDrag(boolean canDrag);

    /**

    * Return drag enable of page.

    */

    public boolean canDrag();

    Set can or can't fling when finger off screen.

    /**

    * Set fling enable for page.

    */

    public void setCanFling(boolean canFling);

    /**

    * Return fling enable of page.

    */

    public boolean canFling();

    Set the visibility of the button for the month of switch.

    /**

    * Set button visible for last month.

    *

    * @param visibility {@link Visibility}

    */

    public void setLastMonthButtonVisibility(@Visibility int visibility);

    /**

    * Set button visible for next month.

    *

    * @param visibility {@link Visibility}

    */

    public void setNextMonthButtonVisibility(@Visibility int visibility);

    Get view of today.

    /**

    * Return item view of today. If today not showing, return null。

    */

    public View getTodayItemView();

    Set the calendar size will wrap content or not. Use this api you can set the calendar size will wrap content or not. if true, the layout's height will auto change with animation when month changed.

    /**

    * Set the layout will wrap content or not.

    *

    * @param scaleEnable if true, the layout will wrap content.

    */

    public void setScaleEnable(boolean scaleEnable);

    Custom UI for date

    You can use default UI for date by SampleVagueAdapter. Default UI only show date.

    calendarView.setVagueAdapter(new SampleVagueAdapter());

    You can custom UI for date by extend VagueAdapter , e.g. custom UI for checkin.

    // layout_checkin_calendar_item must hava a TextView that's id is tv_day_of_month

    calendarView.setVagueAdapter(new MyVagueAdapter(R.layout.layout_checkin_calendar_item));

    private class MyVagueAdapter extends VagueAdapter>> {

    /**

    * @params dateLayout layout resource id for date, must hava a TextView that's id is tv_day_of_month

    */

    MyVagueAdapter(@LayoutRes int dateLayout) {

    super(dateLayout);

    }

    @Override

    public void onBindVague(View itemView, int year, @Month int month, @DayOfMonth int dayOfMonth) {

    // do something, show custom data

    }

    @Override

    public void flagToday(View todayView) {

    // do something, set a flag for today's view

    }

    @Override

    public void flagNotToday(View dayView, Date date) {

    // do something, set a flag for not today's view

    }

    }

    License

    Copyright 2017 StoneHui

    Licensed under the Apache License, Version 2.0 (the "License");

    you may not use this file except in compliance with the License.

    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software

    distributed under the License is distributed on an "AS IS" BASIS,

    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

    See the License for the specific language governing permissions and limitations under the License.

    展开全文
  • Android 数据库自定义日历签到
  • Android日历签到,超级简单的实现方式带来的启发。 先来看一下实现效果: 整体的思路是这样的: 选择使用GridView作为日期的显示,但是需要注意的一点就是需要给GridView设置一个最大尺寸,这个我们可以通过...

       之前一直想写一个android的签到控件,参照了网上的博客,决定自己写一个比较全的。在此感谢

    Android日历签到,超级简单的实现方式 带来的启发。

    先来看一下实现效果:

     

    整体的思路是这样的:

    选择使用GridView作为日期的显示,但是需要注意的一点就是需要给GridView设置一个最大尺寸,这个我们可以通过继承GridView,重载里面的方法来进行实现。

    代码如下:

    public class SignGridView extends GridView {
        public SignGridView(Context context) {
            super(context);
        }
        public SignGridView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
        public SignGridView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
        @Override
        public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 3, MeasureSpec.AT_MOST);
            super.onMeasure(widthMeasureSpec, expandSpec);
        }
    }

     代码不是很多,除了三个必要的构造方法外,在onMeasure方法中,我们给控件设置了一下大小,具体设置可以参考这篇博客

    Android之:了解MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,MeasureSpec.AT_MOST)

    博客里对该属性的说明如下:

     MeasureSpec.AT_MOST是最大尺寸,当控件的layout_width或layout_height指定为WRAP_CONTENT时,控件大小一般随着控件的子空间或内容进行变化,此时控件尺寸只要不超过父控件允许的最大尺寸即可。因此,此时的mode是AT_MOST,size给出了父控件允许的最大尺寸。

    通过Android自带的日历Calendar来实现每月的第一天是星期几,以及每月的总天数,还有当前年月日的获取。

    为了方便使用,我们定义了一个DateUtil工具类,里面定义了实现上述几个功能的方法,由于篇幅限制,这里就不贴完代码了,感兴趣的小伙伴可以在文章的底部找到项目的github地址。

    核心算法部分,通过查询本地数据库的签到数据,与当前界面的年月日进行匹配,若当前页面含有数据库的签到数据,或者说是与数据库的数据有匹配上的,就将GridView中的Item里面的打勾图片显示出来,表示该日期已签到。

    重头戏来了

    对于我们自定义的日期控件SignView,既然是继承自GridView的,适配器adapter的定义可以说是最重要,也是最难的。因为大部分的功能都在这里实现了。

    话不多说,先来看代码:

    public class DateAdapter extends BaseAdapter {
    
        private static final String TAG = "DateAdapter--->>>";
    
        private Context context;
        //日历坐标数据 根据布尔值设置是否签到
        private List<Integer> days = new ArrayList<>();
        //签到状态,用来判断坐标中哪个位置是已经签到的
        private List<Boolean> status = new ArrayList<>();
    
        private List<String> signIns;//数据库查到的签到记录
        private  int maxDay,firstDay,dif; //
    
        private int current_year, current_mon;
    
        private SignInHelper helper;
    
        public interface OnSignListener {
            void OnSignedSucceed();
            void OnSignedFail();
        }
    
        //签到成功的回调方法,相应的可自行添加签到失败时的回调方法
    
        public DateAdapter(Context context, int year, int month) {
            this.context = context;
    
            current_year = year;
            current_mon = month;
    
             helper = new SignInHelper(context);
    
            signIns = helper.query(year,month);
    
    
            Log.i(TAG, "查到的数据:"+signIns);
    
            maxDay = DateUtil.getCurrentMonthLastDay(year,month);//获取当月天数
    
            //firstDay(1-7)  获取当月第一天是星期几,星期日是第一天, 数字为1,代表这个月的第一天是星期天,依次类推
            firstDay = DateUtil.getFirstDayOfMonth(year,month);
    
            //Log.i(TAG, "year:"+year+" mon:"+month+" firstDay:"+firstDay+" maxDay:"+maxDay);
    
            //dif,实际定义的status坐标与日期是有差异的,经过实验和对比后,发现在显示已经签到的日期格子时,
            //显示的位置与实际位置总是有差别,即有时候在签到日期是8号,但是打勾的是6号日期的格子。经过查询规律发现,
            //这个偏差是与firstDay变量有关的,而这个偏差的值为firstDay -2, firstDay取值范围为1-7,这样的话
            //dif取值范围即为(-1,5) 当该月的第一天为星期一时,此时firstDay取值为2,dif为0,此时才不存在偏差 否则
            //其他情况都存在偏差(例如Calendar中默认星期天为第一天,此时的Calendar.DAY_OF_WEEK取值为 1 但
            // gridView默认坐标从0开始,此时需要加上偏差 这时的偏差dif= 1-2=-1)
            dif = firstDay -2;
    
            for (int i = 0; i < firstDay - 1; i++) {
                days.add(0);
                //0代表需要隐藏的item
                status.add(false);
                //false代表为签到状态
            }
    
            for (int i = 0; i < maxDay; i++) {
                days.add(i+1);
                //初始化日历数据
                status.add(false);
                //初始化日历签到状态
            }
            status = DateUtil.dateConvert(current_year, current_mon,signIns,status,dif);
        }
    
        @Override
        public int getCount() {
            return days.size();
        }
    
        @Override
        public Object getItem(int i) {
            return days.get(i);
        }
    
        @Override
        public long getItemId(int i) {
            return i;
        }
    
        @Override
        public View getView(final int i, View view, ViewGroup viewGroup) {
            ViewHolder viewHolder;
            if(view==null){
                view = LayoutInflater.from(context).inflate(R.layout.item_gv,null);
                viewHolder = new ViewHolder();
                view.setTag(viewHolder);
            }else{
                viewHolder = (ViewHolder) view.getTag();
            }
            viewHolder.tv = view.findViewById(R.id.tvWeek);
            viewHolder.rlItem = view.findViewById(R.id.rlItem);
            viewHolder.ivStatus = view.findViewById(R.id.ivStatus);
            viewHolder.tv.setText(days.get(i)+"");
            if(days.get(i)==0){  //接着上个月的残留日期
                viewHolder.rlItem.setVisibility(View.GONE);
            }
            if(status.get(i)){
                viewHolder.tv.setTextColor(Color.parseColor("#FD0000"));
                viewHolder.ivStatus.setVisibility(View.VISIBLE);
            }else{
                viewHolder.tv.setTextColor(Color.parseColor("#666666"));
                viewHolder.ivStatus.setVisibility(View.GONE);
            }
            return view;
        }
    
        class ViewHolder{
            RelativeLayout rlItem;
            TextView tv;
            ImageView ivStatus;
        }
    
        public void signIn(OnSignListener listener){
            helper.insert(DateUtil.CURRENT);
            notifyDataSetChanged();
            listener.OnSignedSucceed();
        }
        public boolean isSign(){
            return status.get(DateUtil.DAY+dif);
        }
    
    }
    
    
     

    代码有点多,逐一解释吧。首先我们将days设置为数据源,以上面第一张图为例,当前月份中,一号为星期六,此时也就意味着,前面的六个位置是没有数据的,对于没有数据的格子,我们将其设置为0。然后在获取视图即getView方法中,通过数据源是否为0控制视图的显示与隐藏。此外还通过一个布尔值类型的List,status辅助记录签到情况,对于已经签到的日期,值设置为true,至于代码中涉及到的偏差dif,逻辑上理解起来可能会有些绕,相关注释在代码中已经写有,这里不再赘述。

    关于往月的签到情况查看,由于android6.0之后的DatePickerDialog都是默认会有年月日三项,但是我们只需要年和月这两项,所以我们需要自定义一个只有年和月选项的日期选择器MonPickerDialog,同理也是通过重载DatePickerDialog实现。

    将MonPickerDialog定义如下:

    public class MonPickerDialog extends DatePickerDialog {
    
        private OnDateSetListener listener;
        public MonPickerDialog(Context context, OnDateSetListener callBack, int year, int monthOfYear, int dayOfMonth) {
            super(context, android.R.style.Theme_Holo_Light_Panel, callBack,year, monthOfYear, dayOfMonth);
            this.setTitle(year + "年" + (monthOfYear + 1) + "月");
            listener = callBack;
            ((ViewGroup) ((ViewGroup) this.getDatePicker().getChildAt(0)).getChildAt(0)).getChildAt(2).
                    setVisibility(View.GONE);
        }
    
        @Override
        public void onDateChanged(DatePicker view, int year, int month, int day) {
            super.onDateChanged(view, year, month, day);
            this.setTitle(year + "年" + (month + 1) + "月");
            listener.onDateSet(view,year,month,day);
        }
    }

     效果如下图:

     

    项目已经发布到github:https://github.com/Domlaa/SignView

     

    如果喜欢的话别忘了点个star,谢谢^_^

    展开全文
  • Android 自定义日历签到效果

    千次阅读 热门讨论 2019-10-04 14:08:57
    自定义日历签到效果

    如果需要更多的定制化需求请直接看我这篇,Android 使用RecycleView自定义日历签到效果
    ,自定义日历2.0的功能远远大于我这个篇1.0的效果。

    效果展示
    在这里插入图片描述

    自定义1.0的效果,适用于需求差不多,拿过来直接使用的。毕竟大家时间宝贵.
    在这里插入图片描述
    这里的这个图标是可以根据自己的需求更换的,比如连续签到有礼包的这种,还有忘记签到状态之类的。

    代码实现

    通过自定义View,把带有日历的Adapter加载到这个View中,然后通过这个View实现 OnTodayClickListener完成签到。

    核心代码

    public class SignView extends View {
        private static final String[] WEEK_MARK = {"一", "二", "三", "四", "五", "六", "日"};
    
        private static final int MAX_COLUMN = 7;
        /**
         * 周内
         */
        private static final int COLOR_MARKER_WEEKDAY = 0xFF999999;
        private static final int COLOR_MARKER_WEEKEND = 0xFF1B89CD;
        /**
         * 已签到背景色
         */
        private static final int COLOR_BACKGROUND_HIGHLIGHT = 0xFF1B89CD;
        /**
         * 未签到背景色
         */
        private static final int COLOR_BACKGROUND_NORMAL = 0xFFFFFFFF;
        /**
         * 等待签到背景色
         */
        private static final int COLOR_BACKGROUND_WAIT = 0xFFFE7471;
        /**
         * 已签到文字颜色
         */
        private static final int COLOR_TEXT_HIGHLIGHT = 0xFFFFFFFF;
        /**
         * 未签到文字颜色
         */
        private static final int COLOR_TEXT_NORMAL = 0xFF606060;
    //    /**
    //     * 不可用文字颜色
    //     */
    //    private static final int COLOR_TEXT_DISABLED = 0xFFD4D4D4;
    
        private static final int MARKER_TEXT_SIZE = 40;
        private static final int CELL_TEXT_SIZE = 40;
    
        private static final int VERTICAL_SPACE = 51;
        private static final int VERTICAL_MARGIN = 62;
        private static final int HORIZONTAL_MARGIN = 39;
        private static final int CELL_SIZE = 80;
        private static final int WAIT_LINE_SIZE = 14;
    
        private int dayOfMonthToday;
        private int markerTextY;
        private int verticalCellTop;
        private int sumDayOfMonth;
        private int daysOfFirstWeek;
        private int horizontalSpace;
        private int deltaTextCellY;
        private int deltaTextMarkerY;
    
        private int verticalSpace;
        private int verticalMargin;
        private int horizontalMargin;
        private int cellSize;
        private int waitLineSize;
    
        private Path waitPath;
        private Rect waitRect;
        private Paint paintWeekday;
        private Paint paintWeekend;
        private Paint paintTextNormal;
        private Paint paintTextHighlight;
        private Paint paintBackgroundWait;
        private Paint paintBackgroundNormal;
        private Paint paintBackgroundHighlight;
        private CalendarAdapter adapter;
        private ResolutionUtil resolutionUtil;
        private Paint paintReward;
        private Paint paintRewardX;
        public SignView(Context context) {
            this(context, null);
        }
    
        public SignView(Context context, AttributeSet attrs) {
            this(context, attrs, -1);
        }
    
        public SignView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            initResolution();
            initPaint();
            initData();
        }
    
        private void initResolution() {
            resolutionUtil = ResolutionUtil.getInstance();
            verticalSpace = resolutionUtil.formatVertical(VERTICAL_SPACE);
            verticalMargin = resolutionUtil.formatVertical(VERTICAL_MARGIN);
            horizontalMargin = resolutionUtil.formatHorizontal(HORIZONTAL_MARGIN);
            cellSize = resolutionUtil.formatVertical(CELL_SIZE);
            waitLineSize = resolutionUtil.formatVertical(WAIT_LINE_SIZE);
        }
    
        private void initPaint() {
            int markerTextSize = resolutionUtil.formatVertical(MARKER_TEXT_SIZE);
            int cellTextSize = resolutionUtil.formatVertical(CELL_TEXT_SIZE);
    
            paintWeekday = new Paint();
            paintWeekday.setAntiAlias(true);
            paintWeekday.setColor(COLOR_MARKER_WEEKDAY);
            paintWeekday.setTextSize(markerTextSize);
            paintWeekday.setTextAlign(Paint.Align.CENTER);
    
            paintWeekend = new Paint();
            paintWeekend.setAntiAlias(true);
            paintWeekend.setColor(COLOR_MARKER_WEEKEND);
            paintWeekend.setTextSize(markerTextSize);
            paintWeekend.setTextAlign(Paint.Align.CENTER);
    
            paintTextNormal = new Paint();
            paintTextNormal.setAntiAlias(true);
            paintTextNormal.setColor(COLOR_TEXT_NORMAL);
            paintTextNormal.setTextSize(cellTextSize);
            paintTextNormal.setTextAlign(Paint.Align.CENTER);
    
            //签到画笔颜色
            paintTextHighlight = new Paint();
            paintTextHighlight.setAntiAlias(true);
            paintTextHighlight.setAlpha(00);//透明度
            paintTextHighlight.setTextSize(cellTextSize);
            paintTextHighlight.setTextAlign(Paint.Align.CENTER);
    
            paintBackgroundWait = new Paint();
            paintBackgroundWait.setAntiAlias(true);
            paintBackgroundWait.setColor(COLOR_BACKGROUND_WAIT);
            paintBackgroundWait.setStrokeWidth(2);
            paintBackgroundWait.setStyle(Paint.Style.STROKE);
    
            //未签到 背景
            paintBackgroundNormal = new Paint();
            paintBackgroundNormal.setAntiAlias(true);
            paintBackgroundNormal.setColor(COLOR_BACKGROUND_NORMAL);
            paintBackgroundNormal.setStrokeWidth(2);
            paintBackgroundNormal.setStyle(Paint.Style.FILL);
    
    
            //已签到 背景
            paintBackgroundHighlight = new Paint();
            paintBackgroundHighlight.setAntiAlias(true);
           // paintBackgroundHighlight.setColor(COLOR_BACKGROUND_HIGHLIGHT);
            paintBackgroundHighlight.setStrokeWidth(2);
            paintBackgroundHighlight.setStyle(Paint.Style.FILL);
    
            //奖项
            paintReward = new Paint();
            paintReward.setAntiAlias(true);
            paintReward.setStrokeWidth(2);
            paintReward.setStyle(Paint.Style.FILL);
    
            paintRewardX = new Paint();
            paintRewardX.setAntiAlias(true);
            paintRewardX.setAlpha(00);//透明度
            paintRewardX.setTextSize(cellTextSize);
            paintRewardX.setTextAlign(Paint.Align.CENTER);
        }
    
        private void initData() {
            Paint.FontMetricsInt fmiMarker = paintWeekday.getFontMetricsInt();
            deltaTextMarkerY = -(fmiMarker.bottom - fmiMarker.top) / 2 - fmiMarker.top;
            markerTextY = verticalMargin + cellSize / 2;
            Paint.FontMetricsInt fmiCell = paintTextNormal.getFontMetricsInt();
            deltaTextCellY = -(fmiCell.bottom - fmiCell.top) / 2 - fmiCell.top;
            verticalCellTop = verticalMargin + cellSize;
    
            Calendar calendarToday = Calendar.getInstance();
            dayOfMonthToday = calendarToday.get(Calendar.DAY_OF_MONTH);
            int dayOfWeek;
            sumDayOfMonth = calendarToday.getActualMaximum(Calendar.DAY_OF_MONTH);
    
            Calendar calendarFirstDay = Calendar.getInstance();
            calendarFirstDay.set(Calendar.DAY_OF_MONTH, 1);
            dayOfWeek = calendarFirstDay.get(Calendar.DAY_OF_WEEK);
            if (dayOfWeek == Calendar.SUNDAY) {
                dayOfWeek = 7;
            } else {
                dayOfWeek = dayOfWeek - 1;
            }
            daysOfFirstWeek = MAX_COLUMN - dayOfWeek + 1;
        }
    
        private void createWaitBackground(int topX, int topY) {
            waitPath = new Path();
            waitPath.moveTo(topX, topY + waitLineSize);
            waitPath.lineTo(topX, topY);
            waitPath.lineTo(topX + waitLineSize, topY);
    
            waitPath.moveTo(topX + cellSize - waitLineSize, topY + cellSize);
            waitPath.lineTo(topX + cellSize, topY + cellSize);
            waitPath.lineTo(topX + cellSize, topY + cellSize - waitLineSize);
    
            waitRect = new Rect(topX, topY, topX + cellSize, topY + cellSize);
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            horizontalSpace = (w - MAX_COLUMN * cellSize - horizontalMargin * 2) / (MAX_COLUMN - 1);
        }
    
        @Override
        public void draw(Canvas canvas) {
            super.draw(canvas);
            drawWeekMark(canvas);
            drawCellsBackground(canvas);
            drawCells(canvas);
        }
    
        private void drawWeekMark(Canvas canvas) {
            int y = markerTextY + deltaTextMarkerY;
            for (int i = 0; i < 7; i++) {
                int x = horizontalMargin + i * (horizontalSpace + cellSize)
                        + cellSize / 2;
                if (i < 5) {
                    canvas.drawText(WEEK_MARK[i], x, y, paintWeekday);
                } else {
                    canvas.drawText(WEEK_MARK[i], x, y, paintWeekend);
                }
            }
        }
    
        private void drawCellsBackground(Canvas canvas) {
            for (int i = 1; i <= dayOfMonthToday; i++) {
                drawCellBackground(canvas, i, getColumnIndex(i), getRowIndex(i));
            }
        }
    
        /**
         * 根据行列序号绘制日期背景
         *
         * @param canvas     画布
         * @param dayOfMonth 日期
         * @param column     列序号
         * @param row        行序号
         */
        private void drawCellBackground(Canvas canvas, int dayOfMonth, int column, int row) {
            int x = horizontalMargin + column * (horizontalSpace + cellSize)
                    + cellSize / 2;
            int y = verticalCellTop + verticalSpace * (row + 1) + cellSize * row + cellSize / 2;
            if (adapter != null) {
                DayType dayType = adapter.getType(dayOfMonth);
                switch (dayType) {
                    case WAITING:
                        if (waitPath == null) {
                            createWaitBackground(x - cellSize / 2, y - cellSize / 2);
                        }
                        canvas.drawPath(waitPath, paintBackgroundWait);
                        break;
                    case SIGNED:
                        canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.icon_m), x-30, y-30, paintBackgroundHighlight);
                        break;
                    case REWARD:
                       canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.icon_j), x-30, y-30, paintReward);
                       // canvas.drawCircle(x, y, cellSize / 2, paintBackgroundNormal);
                        break;
                    default:
                        canvas.drawCircle(x, y, cellSize / 2, paintBackgroundNormal);
                        break;
                }
            } else {
                canvas.drawCircle(x, y, cellSize / 2, paintBackgroundNormal);
            }
        }
    
        private void drawCells(Canvas canvas) {
            for (int i = 1; i <= sumDayOfMonth; i++) {
                drawCell(canvas, i, getColumnIndex(i), getRowIndex(i));
            }
        }
    
        /**
         * 根据行列序号绘制日期
         *
         * @param canvas     画布
         * @param dayOfMonth 日期
         * @param column     列序号
         * @param row        行序号
         */
        private void drawCell(Canvas canvas, int dayOfMonth, int column, int row) {
            int x = horizontalMargin + column * (horizontalSpace + cellSize)
                    + cellSize / 2;
            int y = verticalCellTop + verticalSpace * (row + 1) + cellSize * row + cellSize / 2
                    + deltaTextCellY;
            if (adapter != null && dayOfMonth <= dayOfMonthToday) {
                DayType dayType = adapter.getType(dayOfMonth);
                Paint paint;
                switch (dayType) {
                    case SIGNED:
                        paint = paintTextHighlight;
                        break;
                    case REWARD:
                        paint = paintRewardX;
                        break;
                    default:
                        paint = paintTextNormal;
                        break;
                }
                canvas.drawText(String.valueOf(dayOfMonth), x, y, paint);
            } else {
                canvas.drawText(String.valueOf(dayOfMonth), x, y, paintTextNormal);
            }
        }
    
        /**
         * 获取列序号
         *
         * @param dayOfMonth 日期
         * @return 列序号
         */
        private int getColumnIndex(int dayOfMonth) {
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
            int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
            if (dayOfWeek == Calendar.SUNDAY) {
                dayOfWeek = 6;
            } else {
                dayOfWeek = dayOfWeek - 2;
            }
            return dayOfWeek;
        }
    
        /**
         * 获取行序号
         *
         * @param dayOfMonth 日期
         * @return 行序号
         */
        private int getRowIndex(int dayOfMonth) {
            float weight = (dayOfMonth - daysOfFirstWeek) / (MAX_COLUMN * 1f);
            double rowIndexDouble = Math.abs(Math.ceil(weight));
            return (int) rowIndexDouble;
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_UP) {
                float x = event.getX();
                float y = event.getY();
                if (waitPath != null) {
                    if (adapter.getType(dayOfMonthToday).equals(DayType.WAITING)) {
                        if (x >= waitRect.left && y >= waitRect.top && x <= waitRect.right && y <= waitRect.bottom) {
                            if (onTodayClickListener != null) {
                                onTodayClickListener.onTodayClick();
                            }
                        }
                    }
                }
            }
            return true;
        }
    
        public void setAdapter(CalendarAdapter adapter) {
            this.adapter = adapter;
            this.invalidate();
        }
    
        public int getDayOfMonthToday() {
            return dayOfMonthToday;
        }
    
        public void notifyDataSetChanged() {
            invalidate();
        }
    
        private OnTodayClickListener onTodayClickListener;
    
        public void setOnTodayClickListener(OnTodayClickListener onTodayClickListener) {
            this.onTodayClickListener = onTodayClickListener;
        }
    
        public interface OnTodayClickListener {
            void onTodayClick();
        }
    
        public enum DayType {
            /**
             * 已签到状态,时间已过
             */
            SIGNED(0),
            /**
             * 未签到状态,时间已过
             */
            UNSIGNED(1),
            /**
             * 等待状态,即当日还未签到
             */
            WAITING(2),
            /**
             * 不可达到状态,未到时间
             */
            UNREACHABLE(3),
            /**
             * 不可用状态,非当前月份
             */
            DISABLED(5),
    
            /**
             * 奖赏
             */
            REWARD(4);
    
            private int value;
    
            DayType(int value) {
                this.value = value;
            }
    
            public int getValue() {
                return value;
            }
    
            public static DayType valueOf(int value) {
                switch (value) {
                    case 0:
                        return SIGNED;
                    case 1:
                        return UNSIGNED;
                    case 2:
                        return WAITING;
                    case 3:
                        return UNREACHABLE;
                    case 4:
                        return REWARD;
                    case 5:
                        return DISABLED;
                    default:
                        return DISABLED;
                }
            }
        }
    }
    
    

    【源码地址】

    [希望这篇文章可以帮到你]

    展开全文
  • 日历签到demo 实现记录

    千次阅读 2015-12-02 22:25:13
    Android日历签到
  • Android实现日历签到

    千次阅读 2016-11-13 00:14:47
    实现了日历签到,已经封装起来,可以直接用 http://blog.csdn.net/wushaoge0129/article/details/50826859
  • 主要为大家详细介绍了Android签到日历控件的实现方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • Android-签到日历

    千次阅读 2017-09-09 21:39:51
    项目中签到日历的实现尝试过用Recyclerview实现,用ViewFilper或者ViewPager实现切换动画,功能是实现了,但是第一次启动时,因为Recyclerview要创建多个布局,导致界面卡顿,后来想到可以用自定义View的方式来...
  • Android签到日历控件

    千次阅读 热门讨论 2017-11-24 15:26:43
    最近在公司的功能需求中,需要实现可以签到日历签到后在签到过的日期做标志。本功能参考了网上一些大神的日历控件,在此基础上进行修改,已满足本公司的需求,现已完成,记录一下。布局文件:<RelativeLayout...
  • Android实现签到日历控件

    万次阅读 多人点赞 2016-07-25 15:02:14
    笔者自己考虑了一下设计思路和算法,并且实现了一个可以签到日历控件。其实思路很简单,难点就在日期的绘制上。废话不多说,进入正题吧。效果预览算法设计总体思路设计按照效果图中所示的绘制日历,把每一天当作一...
  • 之前上传过一个自定义签到日历的demo,但是后来发现有点问题,可是csdn又不让删除。只好重新再修改完善一下了。 拓展性很高,可以自己在基础上改动。 还有其它的demo,可以到这里来看看:...
  • 详见代码注释 需要自己微调,目前签到信息存入本地SQLite数据库中了
  • ·最近公司又要求做一个签到日历效果,我为啥加个又是之前我实现了一个日历签到效果,而这次我使用的则是RecycleView去实现。
  • Android例子源码带有数据库存储的自定义日历签到是一个基于安卓的日历签到例子源码,ui界面美观大方,标记清晰。二次开发价值大。可用于移植到oa或者其他需要签到计时的项目中 
  • 该功能是一项Android APP登录时候的签到功能,签到完成画圈标识,以及android的一个汉子验证码功能的实现
  • android签到的自定义日历控件

    千次阅读 多人点赞 2016-07-15 09:14:36
    android签到的自定义日历控件 首先是MainActivity,源码如下 public class MainActivity extends Activity { private SignCalendar calendar; private String date; private int years; private String ...
  • android自定义日历-实现签到订约功能 基于IDEA的工程源码
  • 一个比较详细的自定义的签到日历。简单易懂,可自行修改
  • android 安卓签到日历demo 自定义控件.rar,太多无法一一验证是否可用,程序如果跑不起来需要自调,部分代码功能进行参考学习。
  • android签到日历实现

    万次阅读 多人点赞 2016-03-08 16:48:19
    先看最终实现的效果 事情是这样的,那一天我仍一如既往的在写代码(看新闻),隔了10米远我就看到一个傻。哦 不对 看见我们的经理走了过来。我的内心是这样的。 “怎么样,BUG改的怎么样了?...我们要加一个签到
  • Android快速实现签到日历

    千次阅读 2019-06-13 15:54:29
    市场上很多App都会有签到功能,实现方式不尽相同,有直接展示整张日历的,也有只提供近7日或15日的签到情况的。我遇到的需求是展示一张包含35天的日历,没有翻页功能,但当前日期必须在日历最中间的那一行,我去,...

空空如也

空空如也

1 2 3 4 5 ... 16
收藏数 311
精华内容 124
关键字:

android日历签到