您的位置:首页 > 其它

一款安卓日历(二)

2017-06-27 16:49 309 查看
接上篇博客一款安卓日历(一),这篇文章主要介绍日历滑动切换的细节。

项目地址:https://github.com/yannecer/NCalendar

月视图和周视图滑动切换,是自定义的
MWCalendar
继承
LinearLayout
,实现了
NestedScrollingParent
接口,消费了
RecyclerView
的滑动距离,实现整体上滑,在滑动过程中根据条件判断是否显示周视图
WeekCalendar
,用
OverScroller
实现滚动。

关于
NestedScrollingParent
RecyclerView
的嵌套滑动,网上已经有比较详细的资料,这里不再复制粘贴,只讲一下实现细节,我主要参考了
Hongyang
的照片文章Android NestedScrolling机制完全解析 带你玩转嵌套滑动

MWCalendar

MWCalendar
是一个继承
LinearLayout
,并实现
NestedScrollingParent
的容器,里面包含了一个月视图
MonthCalendar
和一个
RecyclerView
WeekCalendar
是在
xml
加载完后以参数的方式传进去的,目的是为了使
MWCalendar
WeekCalendar
同在一个
RelativeLayout
中方便处理切换,
RecyclerView
向上滑动时,让
NestedScrollingParent
消耗掉
RecyclerView
的上滑距离,当向上滑动到只剩一个行高的时候,
NestedScrollingParent
停止滑动,由
RecyclerView
继续滑动。这里主要说
onStartNestedScroll()
,
onStopNestedScroll()
,
onNestedPreScroll()
onMeasure()
这四个方法。

@Override
public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {

boolean hiddenMonthCalendar = dy > 0 && getScrollY() < rowHeigh * 5;
boolean showMonthCalendar = dy < 0 && getScrollY() >= 0 && !ViewCompat.canScrollVertically(target, -1);

if (hiddenMonthCalendar || showMonthCalendar) {
scrollBy(0, dy);
consumed[1] = dy;
}
}


这个方法在滑动时调用,用来判断月视图和周视图的切换,
dy>0
向上滑,且滑动距离
getScrollY()<rowHeigh * 5(月视图共6个行高)
时,需要月视图向上滑,
滑动距离为rowHeigh * 5


@Override
public void onStopNestedScroll(View target) {

int scrollY = getScrollY();
if (scrollY == 0 || scrollY == rowHeigh * 5) {
return;
}

if (STATE == OPEN) {
if (scrollY > 100) {
startScroll(scrollY,rowHeigh * 5 - scrollY,300);
} else {
startScroll(scrollY, -scrollY, 300);
}
}
if (STATE == CLOSE) {
if (scrollY < rowHeigh * 5 - 100) {
startScroll(scrollY, -scrollY, 300);
} else {
startScroll(scrollY, rowHeigh * 5 - scrollY, 300);
}
}
}

-----------

private void startScroll(int startY,int dy,int duration) {
mScroller.startScroll(0, startY, 0, dy, duration);
invalidate();
}


这个方法是停止滑动手松开的时候调用,在这个方法中根据状态判断是上滚还是下滚,再根据已滑动的距离
getScrollY()
和总的滑动距离得到需要利用
mScroller
滚动的距离。

@Override
public void computeScroll() {
int scrollY = getScrollY();
if (scrollY == 0) {
STATE = OPEN;
weekCalendar.setVisibility(INVISIBLE);
} else if (scrollY == 5 * rowHeigh) {
STATE = CLOSE;
weekCalendar.setVisibility(VISIBLE);
} else {
int weekRow = monthCalendar.getCurrentMothView().getWeekRow();
weekCalendar.setVisibility(scrollY >= weekRow  * rowHeigh ? VISIBLE : INVISIBLE);
}

if (mScroller.computeScrollOffset()) {
scrollTo(0, mScroller.getCurrY());
invalidate();
}
}


computeScroll()
方法,在执行
mScroller.startScroll()
后调用,实时调用并绘制界面,所以可以在这个方法中判断周视图和月视图哪个应该显示。

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
rowHeigh = monthCalendar.getRowHeigh();
ViewGroup.LayoutParams params = recyclerView.getLayoutParams();
params.height = getMeasuredHeight() - rowHeigh;
}


NestedScrollingParent
中如果不重写
onMeasure()
方法,会出现上滑的过程中,下面的部分是空白的,原因是整体
View
测量的时候,测量的结果适应屏幕的大小,在上滑的过程中并没有重新测量,上滑的时候整体
View
一起整体上滑,
View
的高度还是那么高,向上滑出一部分,下面的就变成空白了。所以我们需要做的就是在
View
测量的时候,给
RecyclerView
加高,这样上滑的时候也是正常显示,这个加高不是随便加的,必须是停止滑动的时候正好能显示
RecyclerView
的全部数据,这样就可以计算得到,加高的部分是正常的高度减去上面一行的高度,强行把
RecyclerView
加高已补充上滑出去的那部分视图。

这就是处理滑动切换视图的主要方法和逻辑,完成项目参见:https://github.com/yannecer/NCalendar
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息