美文网首页ITBOXandroid自定义控件Android开源项目
可能是第十好的Android 开源 日历 Calendar 仿小

可能是第十好的Android 开源 日历 Calendar 仿小

作者: 神奇的小蘑菇 | 来源:发表于2017-06-17 14:10 被阅读9694次

SuperCalendar

简介

  • 博主现在工作在一家教育公司,最近公司的产品狗扔过来一个需求,说要做一个可以周月切换的课表,可以展示用户在某一天的上课安排。接到这个任务之后我研究了很多的日历控件,并且抽出了一个calenderlibS。先看一下最后的项目中的效果:
月模式.png
周模式.png
  • 看到本篇文章的同学估计也是实验课或者项目需求中需要一个日历表,当我接到这个需求的时候,当时脑子压根连想都没想,这么通用的控件,GitHub上一搜一大堆不是嘛。可是等到真正做起来的时候,扎心了老铁,GitHub上的大神居然异常的不给力,都是实现了基本功能,能够滑动切换月份,找实现了周月切换功能的开源库很难。终于我费尽千辛万苦找到一个能够完美切换的项目时,你周月切换之后的数据乱的一塌糊涂啊!!!
  • 算了,自己撸一个!!!

项目链接 SuperCalendar

  • 如果你感觉到对你有帮助,欢迎star
  • 如果你感觉对代码有疑惑,或者需要修改的地方,欢迎issue

主要特性

  • 日历样式完全自定义,拓展性强
  • 左右滑动切换上下周月,上下滑动切换周月模式
  • 抽屉式周月切换效果
  • 标记指定日期(marker)
  • 跳转到指定日期

思路

[图片上传失败...(image-bf19df-1513673145313)]

  • Calendar的绘制由CalendarRenderer完成,IDayRenderer实现自定义的日期效果,CalendarAttr中存储日历的属性。
  • 首先看一下Calendar的代码,Calendar主要是初始化Renderer和Attr,然后接受View的生命周期
  • 在OnDraw的时候调用Renderer的onDraw方法,在点击事件onTouchEvent触发时,调用Renderer的点击处理逻辑
    private void initAttrAndRenderer() {
        calendarAttr = new CalendarAttr();
        calendarAttr.setWeekArrayType(CalendarAttr.WeekArrayType.Monday);
        calendarAttr.setCalendarType(CalendarAttr.CalendayType.MONTH);
        renderer = new CalendarRenderer(this , calendarAttr , context);
        renderer.setOnSelectDateListener(onSelectDateListener);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        renderer.draw(canvas);
    }
    private float posX = 0;
    private float posY = 0;
    /*
     * 触摸事件为了确定点击的位置日期
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                posX = event.getX();
                posY = event.getY();
                break;
            case MotionEvent.ACTION_UP:
                float disX = event.getX() - posX;
                float disY = event.getY() - posY;
                if (Math.abs(disX) < touchSlop && Math.abs(disY) < touchSlop) {
                    int col = (int) (posX / cellWidth);
                    int row = (int) (posY / cellHeight);
                    onAdapterSelectListener.cancelSelectState();
                    renderer.onClickDate(col, row);
                    onAdapterSelectListener.updateSelectState();
                    invalidate();
                }
                break;
        }
        return true;
    }
  • 然后看一下CalendarRenderer的代码,Renderer承担了Calendar的绘制任务,首先renderer根据种子日期seedDate填充出Calendar包含的Date数据,calendar中持有一个6*7二维数组来存放日期数据。然后在onDraw的时候通过IDayRenderer来完成对日历的绘制。当点击日期改变了日期的状态时,首先改变对应日期的状态State,然后重绘Calendar。
    private void instantiateMonth() {
        int lastMonthDays = Utils.getMonthDays(seedDate.year, seedDate.month - 1);  // 上个月的天数
        int currentMonthDays = Utils.getMonthDays(seedDate.year, seedDate.month);   // 当前月的天数
        int firstDayPosition = Utils.getFirstDayWeekPosition(seedDate.year, seedDate.month , CalendarViewAdapter.weekArrayType);

        int day = 0;
        for (int row = 0; row < Const.TOTAL_ROW; row++) {
            day = fillWeek(lastMonthDays, currentMonthDays, firstDayPosition, day,              row);
        }
    }

    private int fillWeek(int lastMonthDays, int currentMonthDays, int firstDayWeek,                 int day, int row) {
        for (int col = 0; col < Const.TOTAL_COL; col++) {
            int position = col + row * Const.TOTAL_COL; // 单元格位置
            if (position >= firstDayWeek && position < firstDayWeek +               currentMonthDays) { // 本月的
                day ++;
                fillCurrentMonthDate(day, row, col);
            } else if (position < firstDayWeek) { //last month
                instantiateLastMonth(lastMonthDays, firstDayWeek, row, col,                 position);
            } else if (position >= firstDayWeek + currentMonthDays) {//next month
                instantiateNextMonth(currentMonthDays, firstDayWeek, row, col,              position);
            }
        }
        return day;
    }
    
    public void draw(Canvas canvas) {
        for (int row = 0; row < Const.TOTAL_ROW; row++) {
            if (weeks[row] != null) {
                for (int col = 0; col < Const.TOTAL_COL; col ++) {
                    if (weeks[row].days[col] != null) {
                        dayRenderer.drawDay(canvas , weeks[row].days[col]);
                    }
                }
            }
        }
    }
    
    public void onClickDate(int col, int row) {
        if (col >= Const.TOTAL_COL || row >= Const.TOTAL_ROW)
            return;
        if (weeks[row] != null) {
            if(attr.getCalendarType() == CalendarAttr.CalendayType.MONTH) {
                if(weeks[row].days[col].getState() == State.CURRENT_MONTH){
                    weeks[row].days[col].setState(State.SELECT);
                    selectedDate = weeks[row].days[col].getDate();
                    CalendarViewAdapter.saveDate(selectedDate);
                    onSelectDateListener.onSelectDate(selectedDate);
                    seedDate = selectedDate;
                } else if (weeks[row].days[col].getState() == State.PAST_MONTH){
                    selectedDate = weeks[row].days[col].getDate();
                    CalendarViewAdapter.saveDate(selectedDate);
                    onSelectDateListener.onSelectOtherMonth(-1);
                    onSelectDateListener.onSelectDate(selectedDate);
                } else if (weeks[row].days[col].getState() == State.NEXT_MONTH){
                    selectedDate = weeks[row].days[col].getDate();
                    CalendarViewAdapter.saveDate(selectedDate);
                    onSelectDateListener.onSelectOtherMonth(1);
                    onSelectDateListener.onSelectDate(selectedDate);
                }
            } else {
                weeks[row].days[col].setState(State.SELECT);
                selectedDate = weeks[row].days[col].getDate();
                CalendarViewAdapter.saveDate(selectedDate);
                onSelectDateListener.onSelectDate(selectedDate);
                seedDate = selectedDate;
            }
        }
    }
  • 调用Renderer的draw方法时使用dayRenderer.drawDay(canvas , weeks[row].days[col]),dayRenderer是一个接口,在lib中有一个DayView 的抽象类实现该接口。 其中的drawDay方法完成了对该天到calendar的canvas上的绘制
    @Override
    public void drawDay(Canvas canvas , Day day) {
        this.day = day;
        refreshContent();
        int saveId = canvas.save();
        canvas.translate(day.getPosCol() * getMeasuredWidth(),
                day.getPosRow() * getMeasuredHeight());
        draw(canvas);
        canvas.restoreToCount(saveId);
    }
  • 使用继承自ViewPager的MonthPager来存放calendar的view
    viewPageChangeListener = new ViewPager.OnPageChangeListener() {}
    //新建viewPagerChangeListener
    @Override
    protected void onSizeChanged(int w, int h, int oldW, int oldH) {
        cellHeight = h / 6;
        super.onSizeChanged(w, h, oldW, oldH);
    }//重写onSizeChanged,获取dayView的高度
    public int getTopMovableDistance() {
        CalendarViewAdapter calendarViewAdapter = (CalendarViewAdapter)             getAdapter();
        rowIndex = calendarViewAdapter.getPagers().get(currentPosition %            3).getSelectedRowIndex();
        return cellHeight * rowIndex;
    }//计算周月切换时在到达选中行之前MonthPager收起的距离
    public int getRowIndex() {
        CalendarViewAdapter calendarViewAdapter = (CalendarViewAdapter)             getAdapter();
        rowIndex = calendarViewAdapter.getPagers().get(currentPosition  %           3).getSelectedRowIndex();
        Log.e("ldf","getRowIndex = " + rowIndex);
        return rowIndex;
    }//计算选中日期所在的行数
  • 使用CalendarViewAdapter为MonthPager填充calendar的实例
    @Override
    public void setPrimaryItem(ViewGroup container, int position, Object object) {
        super.setPrimaryItem(container, position, object);
        this.currentPosition = position;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {

        if(position < 2){
            return null;
        }
        Calendar calendar = calendars.get(position % calendars.size());
        if(calendarType == CalendarAttr.CalendayType.MONTH) {
            CalendarDate current = seedDate.modifyMonth(position - MonthPager.CURRENT_DAY_INDEX);
            current.setDay(1);//每月的种子日期都是1号
            calendar.showDate(current);
        } else {
            CalendarDate current = seedDate.modifyWeek(position - MonthPager.CURRENT_DAY_INDEX);
            if(weekArrayType == 1) {
                calendar.showDate(Utils.getSaturday(current));
            } else {
                calendar.showDate(Utils.getSunday(current));
            }//每周的种子日期为这一周的最后一天
            calendar.updateWeek(rowCount);
        }
        if (container.getChildCount() == calendars.size()) {
            container.removeView(calendars.get(position % 3));
        }
        if(container.getChildCount() < calendars.size()) {
            container.addView(calendar, 0);
        } else {
            container.addView(calendar, position % 3);
        }
        return calendar;
    }
  • 日历在切换周月时切换日历中填充的数据
  • 在月模式切换成周模式时,将当前页的seedDate拿出来刷新本页数据,并且更新指定行数的周数据,然后得到seedDate下一周的周日作为下一页的seedDate,刷新下一页的数据,并且更新指定行数的周数据。上一页同理
  • 也是说假设我当前选择的是6月12号周日,处于日历的第二行,也是说下一页的seedDate是6月19号,然后刷新6月19号所在周的数据到选定的第二行。
  • 当切换周月时,把三页的数据都会重新刷新一遍,以保证数据的正确性。
    public void switchToMonth() {
        if(calendars != null && calendars.size() > 0 && calendarType !=             CalendarAttr.CalendayType.MONTH){
            calendarType = CalendarAttr.CalendayType.MONTH;
            MonthPager.CURRENT_DAY_INDEX = currentPosition;
            Calendar v = calendars.get(currentPosition % 3);//0
            seedDate = v.getSeedDate();

            Calendar v1 =  calendars.get(currentPosition % 3);//0
            v1.switchCalendarType(CalendarAttr.CalendayType.MONTH);
            v1.showDate(seedDate);

            Calendar v2 = calendars.get((currentPosition - 1) % 3);//2
            v2.switchCalendarType(CalendarAttr.CalendayType.MONTH);
            CalendarDate last = seedDate.modifyMonth(-1);
            last.setDay(1);
            v2.showDate(last);

            Calendar v3 = calendars.get((currentPosition + 1) % 3);//1
            v3.switchCalendarType(CalendarAttr.CalendayType.MONTH);
            CalendarDate next = seedDate.modifyMonth(1);
            next.setDay(1);
            v3.showDate(next);
        }
    }

    public void switchToWeek(int rowIndex) {
        rowCount = rowIndex;
        if(calendars != null && calendars.size() > 0 && calendarType !=             CalendarAttr.CalendayType.WEEK){
            calendarType = CalendarAttr.CalendayType.WEEK;
            MonthPager.CURRENT_DAY_INDEX = currentPosition;
            Calendar v = calendars.get(currentPosition % 3);
            seedDate = v.getSeedDate();

            rowCount = v.getSelectedRowIndex();

            Calendar v1 =  calendars.get(currentPosition % 3);
            v1.switchCalendarType(CalendarAttr.CalendayType.WEEK);
            v1.showDate(seedDate);
            v1.updateWeek(rowIndex);

            Calendar v2 = calendars.get((currentPosition - 1) % 3);
            v2.switchCalendarType(CalendarAttr.CalendayType.WEEK);
            CalendarDate last = seedDate.modifyWeek(-1);
            if(weekArrayType == 1) {
                v2.showDate(Utils.getSaturday(last));
            } else {
                v2.showDate(Utils.getSunday(last));
            }//每周的种子日期为这一周的最后一天
            v2.updateWeek(rowIndex);

            Calendar v3 = calendars.get((currentPosition + 1) % 3);
            v3.switchCalendarType(CalendarAttr.CalendayType.WEEK);
            CalendarDate next = seedDate.modifyWeek(1);
            if(weekArrayType == 1) {
                v3.showDate(Utils.getSaturday(next));
            } else {
                v3.showDate(Utils.getSunday(next));
            }//每周的种子日期为这一周的最后一天
            v3.updateWeek(rowIndex);
        }
    }
  • 使用CoordinateLayout的特性来做周月模式切换
  • 1.RecyclerViewBehavior
    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, RecyclerView child,
                                       View directTargetChild, View target, int nestedScrollAxes) {
        LinearLayoutManager linearLayoutManager = (LinearLayoutManager) child.getLayoutManager();
        if(linearLayoutManager.findFirstCompletelyVisibleItemPosition() > 0) {
            return false;
        }

        boolean isVertical = (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
        int firstRowVerticalPosition =
                (child == null || child.getChildCount() == 0) ? 0 : child.getChildAt(0).getTop();
        boolean recycleviewTopStatus = firstRowVerticalPosition >= 0;
        return isVertical && (recycleviewTopStatus || !Utils.isScrollToBottom()) && child == directTargetChild;
    }

    @Override
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, RecyclerView             child,
                                  View target, int dx, int dy, int[] consumed) {
        super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
        if (child.getTop() <= initOffset && child.getTop() >= minOffset) {
            consumed[1] = Utils.scroll(child, dy, minOffset, initOffset);
            saveTop(child.getTop());
        }
    }

    @Override
    public void onStopNestedScroll(final CoordinatorLayout parent, final        RecyclerView child, View target) {
        Log.e("ldf","onStopNestedScroll");
        super.onStopNestedScroll(parent, child, target);
        if (!Utils.isScrollToBottom()) {
            if (initOffset - Utils.loadTop() > Utils.getTouchSlop(context)){
                scrollTo(parent, child, minOffset, 200);
            } else {
                scrollTo(parent, child, initOffset, 80);
            }
        } else {
            if (Utils.loadTop() - minOffset > Utils.getTouchSlop(context)){
                scrollTo(parent, child, initOffset, 200);
            } else {
                scrollTo(parent, child, minOffset, 80);
            }
        }
    }
  • (2)MonthPagerBehavior 当recyclerView滑动式,MonthPager做相应的变化。
@Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, MonthPager child, View dependency) {
        Log.e("ldf","onDependentViewChanged");
        CalendarViewAdapter calendarViewAdapter = (CalendarViewAdapter) child.getAdapter();
        if (dependentViewTop != -1) {
            int dy = dependency.getTop() - dependentViewTop;    //dependency对其依赖的view(本例依赖的view是RecycleView)

            int top = child.getTop();

            if( dy > touchSlop){
                calendarViewAdapter.switchToMonth();
            } else if(dy < - touchSlop){
                calendarViewAdapter.switchToWeek(child.getRowIndex());
            }

            if (dy > -top){
                dy = -top;
            }

            if (dy < -top - child.getTopMovableDistance()){
                dy = -top - child.getTopMovableDistance();
            }

            child.offsetTopAndBottom(dy);
        } else {
            initRecyclerViewTop = dependency.getTop();
        }

        dependentViewTop = dependency.getTop();
        top = child.getTop();

        if((initRecyclerViewTop - dependentViewTop) >= child.getCellHeight()) {
            Utils.setScrollToBottom(false);
            calendarViewAdapter.switchToWeek(child.getRowIndex());
            initRecyclerViewTop = dependentViewTop;
        }
        if((dependentViewTop - initRecyclerViewTop) >= child.getCellHeight()) {
            Utils.setScrollToBottom(true);
            calendarViewAdapter.switchToMonth();
            initRecyclerViewTop = dependentViewTop;
        }

        return true;
        // TODO: 16/12/8 dy为负时表示向上滑动,dy为正时表示向下滑动,dy为零时表示滑动停止
    }
  • 使用IDayRender来实现自定义的日历效果

DayView实现IDayRenderer,我们新建一个CustomDayView继承自DayView,在里面作自定义的显示

public CustomDayView(Context context, int layoutResource) {
       super(context, layoutResource);
       dateTv = (TextView) findViewById(R.id.date);
       marker = (ImageView) findViewById(R.id.maker);
       selectedBackground = findViewById(R.id.selected_background);
       todayBackground = findViewById(R.id.today_background);
   }

   @Override
   public void refreshContent() {
       renderToday(day.getDate());
       renderSelect(day.getState());
       renderMarker(day.getDate(), day.getState());
       super.refreshContent();
   }

使用方法

XML布局

  • 新建XML布局

RecyclerView的layout_behavior为com.ldf.calendar.behavior.RecyclerViewBehavior

 <android.support.design.widget.CoordinatorLayout
        android:id="@+id/content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1">

        <com.ldf.calendar.view.MonthPager
            android:id="@+id/calendar_view"
            android:layout_width="match_parent"
            android:layout_height="300dp"
            android:background="#fff">
        </com.ldf.calendar.view.MonthPager>

        <android.support.v7.widget.RecyclerView
            android:id="@+id/list"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_behavior="com.ldf.calendar.behavior.RecyclerViewBehavior"
            android:background="#c2c2c2"
            android:layout_gravity="bottom"/>

    </android.support.design.widget.CoordinatorLayout>
    

自定义日历样式

  • 新建CustomDayView继承自DayView并重写refreshContent 和 copy 两个方法
    @Override
    public void refreshContent() {
        //你的代码 你可以在这里定义你的显示规则
        super.refreshContent();
    }

    @Override
    public IDayRenderer copy() {
        return new CustomDayView(context , layoutResource);
    }
  • 新建CustomDayView实例,并作为参数构建CalendarViewAdapter
    CustomDayView customDayView = new CustomDayView(
            context , R.layout.custom_day);
    calendarAdapter = new CalendarViewAdapter(
                context ,
                onSelectDateListener ,
                Calendar.MONTH_TYPE ,
                customDayView);

初始化View

  • 目前来看 相比于Dialog选择日历 我的控件更适合于Activity/Fragment在Activity的onCreate 或者Fragment的onCreateView 你需要实现这两个方法来启动日历并装填进数据
@Override
   protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_syllabus);
        initCalendarView();
    }
    
    private void initCalendarView() {
        initListener();
        CustomDayView customDayView = new CustomDayView(
            context , R.layout.custom_day);
        calendarAdapter = new CalendarViewAdapter(
                context ,
                onSelectDateListener ,
                Calendar.MONTH_TYPE ,
                customDayView);
        initMarkData();
        initMonthPager();
    } 

使用此方法回调日历点击事件

private void initListener() {
        onSelectDateListener = new OnSelectDateListener() {
            @Override
            public void onSelectDate(CalendarDate date) {
                //your code
            }

            @Override
            public void onSelectOtherMonth(int offset) {
                //偏移量 -1表示上一个月 , 1表示下一个月
                monthPager.selectOtherMonth(offset);
            }
        };
    }

使用此方法初始化日历标记数据

private void initMarkData() {
       HashMap markData = new HashMap<>();
        //1表示红点,0表示灰点
       markData.put("2017-8-9" , "1");
       markData.put("2017-7-9" , "0");
       markData.put("2017-6-9" , "1");
       markData.put("2017-6-10" , "0");
       calendarAdapter.setMarkData(markData);
   }

使用此方法给MonthPager添加上相关监听

monthPager.addOnPageChangeListener(new MonthPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            }

            @Override
            public void onPageSelected(int position) {
                mCurrentPage = position;
                currentCalendars = calendarAdapter.getAllItems();
                if(currentCalendars.get(position % currentCalendars.size()) instanceof Calendar){
                    //you code
                }
            }

            @Override
            public void onPageScrollStateChanged(int state) {
            }
        });

重写onWindowFocusChanged方法,使用此方法得知calendar和day的尺寸

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if(hasFocus && !initiated) {
            CalendarDate today = new CalendarDate();
            calendarAdapter.notifyDataChanged(today);
            initiated = true;
        }
    }
  • 大功告成,如果还不清晰,请下载DEMO

Download


Gradle:
Step 1. Add it in your root build.gradle at the end of repositories:

allprojects {
    repositories {
    ...
    maven { url 'https://www.jitpack.io' }
    }
}

Step 2. Add the dependency

    dependencies {
            compile 'com.github.MagicMashRoom:SuperCalendar:1.6'
    }

[图片上传失败...(image-526acb-1513673145313)]

Licence

  Copyright 2017 MagicMashRoom, Inc.

相关文章

网友评论

  • 975bb58577df:大神你的git Demo 也不是你效果图这样啊,我的需求跟您效果图一模一样,跪求效果图源码QQ:764732396
  • yann02:public void setIntentDate(CalendarDate date) {
    currentDate = date;
    tvYear.setText(date.getYear() + "年");
    tvMonth.setText(date.getMonth() + "");
    if (tv_date != null) {
    String yearStr = currentDate.getYear() + "";
    String monStr = String.format("%02d", currentDate.getMonth());
    StringBuilder stbuild = new StringBuilder();
    stbuild.append(yearStr).append(context.getString(R.string.calendar_year)).append(monStr).append(context.getString(R.string.calendar_month));
    LogUtil.i(TAG, "设置年月4-1-1:" + stbuild.toString());
    tv_date.setText(stbuild.toString());
    }
    selectDateListener.onSelectDate(date);
    calendarAdapter.notifyDataChanged(date);
    }

    大佬,我这样写有什么问题吗?我设置以后日历控件的指定日期背景色没有改变,怎么办啊?
  • yann02:大佬,怎么设置日历显示到指定的日期啊?
  • 勤息嘻嘻嘻:大神我想实现一个周视图左右滑动Recyclerview切换日期,月视图左右滑动Recyclerview切换月,是改RecyclerViewBehavior这个文件吗?如何判断是横向滑动呢?
  • 蚂蚁放风筝:请问这个可以同时在日历上面和下面绘制点吗?
  • userCwb:大神,滑动到下个月,网路请求加载数据,之后,数据就错乱了,月份也不对了
  • 知吾煮:默认初始化周列表不管用
  • Y_24a6:选择的时候会出现样式bug
  • 不忘初心方得始終_d827:首先很感谢博主能开源这个项目,让我省下了大量的开发时间(就算有我也开发不出来),在使用中发现博主的控件在选择日期会出现重复选择,这应该跟想联合协调者布局来实现周的显示有关,而我的需求很简单,一下午的探索,把重复选择的问题解决了,在Demo里将CalendarViewAdapter,java类的68行invalidateCurrentCalendar();该方法注释掉就行了。。。。。
    a3e9c6c27a72:谢谢你解决了我的问题
  • 魔酷粉蓝:你好,这个只能显示6行,请问能实现5行显示的全本月数据显示5行,显示不全显示6行吗?很多月份最后一行都是下月数据
  • yginer:大神, 日历设置mark的时候, 日期的格式貌似不能设置为"2018-03-03"这种样式, 必须是"2018-3-3", 这个样子应该是有点问题吧
  • 54ad8864f281:请问作者 怎么让monthpager也能上下滑动收起呢?有什么思路吗?
  • 54ad8864f281:请问下supercalendar怎么获取周日历和月日历的第一天和最后一天日期呢? 就是当前显示的第一天日期和最后一天日期,谢谢!
  • sirai:您好 作者。我这里还有一个需求 就是说日期只展示截止到本月 下个月的数据 以后的都不展示
    sirai:@sirai 作者 我需要的其实不是隐藏 如果当前展示的是本年本月 禁止右滑
    sirai:@神奇的小蘑菇 我明天试试
    神奇的小蘑菇:@sirai 在refreshContent中判断是否为本月然后隐藏
  • shensir_aye:大神你好,我是做iOS开发的,也遇到你这个需求,请问你们做iOS开发的能把这个开源吗
    金银岛:iOS也有很多蛮优秀的开源日历控件, GitHub 上直接搜索 calendar 即可
    神奇的小蘑菇:@shensir_aye 换公司了 不知道原公司的同事有没有开源

    我给你问问
  • 六花垂冰丸:希望能在代码中多加点注释= =
  • 六花垂冰丸:楼主,如果我加一个新的状态,比如改变某天的颜色。为什么不行的啊?
  • 0642f65192e1:连续点击切换月份会出现重月的情况
  • Mr_Tu:请问下,就是我想把当月的day,在下个月或者上个月同样显示。我在onPageSelected中添加了calendarAdapter.notifyDataChanged(new CalendarDate(currentDate.getYear(),currentDate.getMonth(),date.getDay()))。在点击上一个和下一个月的时候是会选中。但是滑动的时候就不会选中。没想明白!!
  • b29d291565f3:怎么动态设置日历的高度? 有时候只需要显示5排
  • 0ea6f257cf54:大神请问 报 MonthPager Just Can Use Own OnPageChangeListener 这问题是什么原因造成的,谢谢!!!
    神奇的小蘑菇:@Tel恒 monthpager继承自viewpager monthpager只能用自己的listener
    神奇的小蘑菇:@Tel恒 monthpager有自己的onpagechangelistener 但是我的calendar只能用我规定的listener
  • d65b79522cfa:博主有一个很奇怪的问题,用你的日历的控件,导入到我的app中就显示3列
    getMeasuredWidth()==77
    canvas.getWidth()==1920
    我打印了下,发现是这两个问题,日历画布的宽度永远都是我手机屏幕的宽度,点击事件都是根据画布的宽度来设置的,但是我把代码赋值到别的model上又发现没有这种问题,这个捆蹄困扰了我好久好久,希望博主能有时间回答这我这个问题,谢谢
  • 8df3c4d3e82d:博主,关于你写的那个日历,我转到我的项目后calendarAdapter.setMarkData(markData);,UI并没有更新,任意点击一下,才更新 是什么问题呢 ?! 能不能加个Q帮一下忙,谢谢!Q2277952561
    54ad8864f281:你是异步加的setMarkData吧
  • d919af51c7db:滑动recyclerview有问题
  • b29d291565f3:为什么设置了左右边距之后日期的排版对不齐了??
  • b29d291565f3:怎么把周日换到第一列?
  • 75f2eec7aca9:在fragment里用CoordinatorLayout时,RecyclerView会把日历盖住,能否给个在fragment里使用的例子?谢谢
  • 天津卓朗科技:楼主留个联系方式 QQ什么的,有几个问题和bug需要沟通
  • b119dca61eab:LZ 我在点击时很卡顿,在上个月和下个月卡顿的更厉害,不显示效果~
    看到+下QQ :1241035319
  • 理幻:震惊了,我想在recyclerview和monthPager间加一些布局要如何操作?总是会报adapter.notifi...(CalendarDate)中有角标越界是什么情况?怎么解决这两个问题?大神求解,急。
  • SuperGentleYu:大哥,我想把周日作为一周的开始,我在你源码里修改了
    //周排列方式 1:代表周日显示为本周的第一天
    //0:代表周一显示为本周的第一天
    public static int weekArrayType = 1;
    没有效果啊
    SuperGentleYu:解决了。哈哈
  • b32fcc0d3453:楼主,报个bug, 当RecyclerView里item较少没有超出屏幕的时候,上下滑动不停地切换月视图和周视图,有一定概率会出现日历下面显示空白的情况,目前我还没找到必现步骤。
    Github上别的网友也发现了这个问题,提到Issues里了 (https://github.com/MagicMashRoom/SuperCalendar/issues/57),请楼主有关关注下,谢谢。
  • SuperGentleYu:大神,给个QQ好么?我项目里引入你 compile 'com.github.MagicMashRoom:SuperCalendar:v1.4'
    会报超时。求帮助
    神奇的小蘑菇: @SuperGentleYu 嗯呢
    SuperGentleYu:@神奇的小蘑菇 大哥,这个版本没问题呗 ?别人引入也可以的?
    神奇的小蘑菇: @SuperGentleYu 这个我也不知道怎么帮助你
  • AD小白:你好,我使用了您的superCalendar日历组件,过程中发现日历一经加载显示当前月,种子日期为今天是正确的,但是滑动viewPager后种子日期被初始化为每个月的1日也是没问题的,我现在想在滑回当前月的时候种子日期为今天,但是查看代码没有找到合适的位置添加当前月的当前日为种子日期,请问有没有合适的位置添加,谢谢!期待您的回复...
    神奇的小蘑菇: @AD小白 就是calendaradapter的initiativeItem那个地方
  • FendovyT_T:不错,但是不支持android4.3呀,demo直接闪退,5.1以上的没事:sweat:
  • Empty_e61d:大神,跳转指定日期在哪?
  • e7fa46c17820:大佬,monthPager.setViewheight(Utils.dpi2px(context, 270));这里我设置成小于270的话,日历会显示不全,我想让日历的行距缩小一点,可以实现么
    e7fa46c17820:@神奇的小蘑菇 你是指在xml文件中设置MonthPager的高度么?不好使啊,还是有别的属性?
    神奇的小蘑菇:@大树爱polo 日历行距在xml文件中设置
  • jiamws:我想弄的是单行日历模式 下面不需要跟着RecyclerView 怎么处理呀 你的那个滑动的代码必须传入一个view
  • llg90:怎么在MonthPager和RecyclerView中间加一个固定高度的布局
  • cd74a6aa8043:请问一下:如何默认显示周,而并非显示月
  • GYLEE:请问 背后的灰色和橙色的圆点怎样添加
  • 闪闪发光的神经病o:您好,请问支持第一列从周日或者从周1开始设置吗?
    神奇的小蘑菇: @闪闪发光的神经病o 读源码
  • 半世浮沉_603c:楼主大大,如何加上农历啊?
    神奇的小蘑菇: @半世浮沉_603c dayview会回调给你阳历日期 你自己转成农历就好
  • 5203f4ad6b44:亲我有个问题需要你帮忙。我想实现个点击一天选中这一周的所有日期效果,但是只找到一行 CalendarViewAdapter.saveDate(selectedDate);这个方法里也没有相关的显示代码,实在是找不到了,先谢谢啦
  • 失落的胡某某: 有个报错。看不明白-.-

    Caused by: java.lang.NullPointerException
    at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:548)
    at android.view.View.measure(View.java:16840)
    at com.ldf.calendar.view.DayView.setupLayoutResource(DayView.java:44)
    at com.ldf.calendar.view.DayView.<init>(DayView.java:32)
    at com.xunjian.musen.widget.superCalendar.CustomDayView.<init>(CustomDayView.java:35)
    失落的胡某某:@FendovyT_T 木有解决,好像是系统错误,看不懂。
    FendovyT_T:我跟你一个问题,你是怎么解决的??:sweat:
    失落的胡某某:楼主方便的话加我qq 504821602 可以详细截图。手机是三星not3.谢谢
  • 70fe9151b662:想问下 怎么才能实现 不用滑动下面的Recyclerview 上下滑动日历就可以控制日历周月切换啊 ..
    54ad8864f281:你解决了吗?上下滑动日历控制月历周历切换
  • RMaple_Qiu:正想做个日历,跟着作者大大学习了
  • 傲娇强:compile 'com.github.MagicMashRoom:SuperCalendar:v1.3.1'
    这个版本不对吧,和直接下载model的代码都不一样
    d65b79522cfa:博主有一个很奇怪的问题,用你的日历的控件,导入到我的app中就显示3列
    getMeasuredWidth()==77
    canvas.getWidth()==1920
    我打印了下,发现是这两个问题,日历画布的宽度永远都是我手机屏幕的宽度,点击事件都是根据画布的宽度来设置的,但是我把代码赋值到别的model上又发现没有这种问题,这个捆蹄困扰了我好久好久,希望博主能有时间回答这我这个问题,谢谢
    神奇的小蘑菇: @傲娇强 新修改的内容还没有发布版本
  • 失落的胡某某:请问。怎么默认是单行显示呢。下滑在展开。calendarAdapter = new CalendarViewAdapter(
    this,
    onSelectDateListener,
    CalendarAttr.CalendayType.WEEK,
    customDayView);
    这个第三个参数已经设置为week了但是没有用。谢谢
    Ignite_hh:@失落的胡某某 你那边实现的week模式,可以么?外层不是使用的CoordinatorLayout布局来的做,这个可以实现么?
    神奇的小蘑菇: @失落的胡某某 你直接去github上 他们问过相似的问题
    神奇的小蘑菇: @失落的胡某某 https://github.com/MagicMashRoom/SuperCalendar/issues/12
  • 失落的胡某某:楼主,我又来了。下滑展示月份,上滑展示周,RecyclerView滑动事件稍微有些冲突,能不能把滑动展开为月份和周的功能关闭?谢谢楼主。
    贝贝ovo:@神奇的小蘑菇 不用recyclerview呢?控件是绑定必须使用recyclerview,这个有些不灵活
    隐居士:有的时候点击底部日期比如3月20号 那么在第一行里也会有一个3月20号备选中 以此类推3月21 会有两个3月21 是bug吧 怎么改啊 楼主
    神奇的小蘑菇: @失落的胡某某 把recyclerview.setNestedScrollingEnabled为false
  • 失落的胡某某:楼主楼主,刚好有个项目用到单行滑动的日历。但是我这有个问题。需求是让日历只显示到当天。有地方设置吗?比如:日历只显示到今天7月21号。也不让他滑动了。谢谢楼主!
    失落的胡某某:@神奇的小蘑菇 好的。明后天我试试。楼主能帮我看看上一个问题吗?下滑展开的问题。感谢感谢:kissing_heart:
    神奇的小蘑菇: @失落的胡某某 monthpager继承自viewpager 你直接重写monthpager让他不左右划 怎么不左右划百度一下就有
  • 神奇的小蘑菇:还有很多问题,希望大家多多指正,开源项目的真谛就是参与和沟通:smile:
    cd74a6aa8043:看到你的更新日志,换成1.4了,完美解决。
    cd74a6aa8043:嗨,朋友,使用你的控件出现了这样一个问题,纠缠了很长时间。。。我的日历只显示6列,还有一列在最右边看不见,但是能点到。
    b23bf91c2aa7:开源项目的真谛就是参与和沟通!为这句话点赞
  • ed6918f57426:请问gif图怎么做?
  • ed6918f57426:你去看看我做的项目 小小军团合战三国 应用宝可以搜到
    ed6918f57426:@神奇的小蘑菇 这是我们公司做的游戏,我只是想打个广告:smirk:
    神奇的小蘑菇: @清风折柳 你让我看这个应用啥意思呢?你要用到我的日历的什么东西吗?
  • ed6918f57426:refreshClickDate这个方法在哪?initMonthPager方法又在哪?
    神奇的小蘑菇: @清风折柳 demo看一下的话 你应该就会明白
    神奇的小蘑菇: @清风折柳 你应该好好看看demo 这两个方法都应该替换成你自己的代码 而不是用我的
  • ed6918f57426:少好多东西
  • 神奇的小蘑菇:有问题直接提issue
  • 神奇的小蘑菇:添加了按钮点击切换周月功能
  • 神奇的小蘑菇:修改了一个问题 该问题当点击按钮切换周月模式时 导致模式 和 数据不正确

本文标题:可能是第十好的Android 开源 日历 Calendar 仿小

本文链接:https://www.haomeiwen.com/subject/bpavqxtx.html