Android 4.0日历(calendar)源码分析之日视图

泡在网上的日子 / 文 发表于2013-03-05 23:20 次阅读 calendar

日视图

相比其他的视图,日视图会显得很“简单”,说简单是因为在日视图下,除了actionbar之外没有任何其他可见的控件,唯一的控件是ViewSwitcher,但是是不可见的。ViewSwitcher里面装着两个显示日信息的自定义View—DayView。这两个View交替着切换,这使得我们能在日视图中一天一天的横向滚动。

 

ViewSwitcher不说了,这里要说的是这个DayView。

DayView是一个完全自定义的View,直接继承至View类。一般我们都是继承一些现成的控件,比如TextView,但是这里直接是将需要的东西一点一点的画出来,所以要弄懂,可能需要对android canvas绘图方面有比较多的了解。DayView的重点和难点有如下几个:

 

如何画出每天需要的信息,比如在恰当的位置画出每个小时的数字和横线,以及当天存在的事件。

如何实现在手指水平左右拖动时,能够看到天与天之间的过度效果;如何在垂直滚动时,响应用户的意图,并保证基本不和水平滚动冲突。

 

第一个问题纯粹是canvas方面的问题,很琐碎,但是逻辑不是那么强。

第二个问题涉及到触摸设备中的手势处理,要做到日历这么人性化的效果,还是比较难的。

 

 

DayView中的手势处理结合了比较原始的onTouchEvent()方法和GestureDetector(封装好了常用的几种手势)。onTouchEvent首先捕获触摸事件,将这个事件,传递给GestureDetector,然后交给GestureDetector分析。根据GestureDetector中的数据,我们得到一些有用的数值(比如在scroll滚动事件发生的时候,我们不断获取滚动点的水平偏移量,然后响应的View也移动相同的偏移量,从而实现水平滑动),然后根据这些数据来重绘View-即调用view的onDraw函数。

给出一小段代码让你找到感觉,不必细究每句话的含义,只需明白大致的处理方式,在ondraw开始几行有如下代码:

float yTranslate = -mViewStartY + DAY_HEADER_HEIGHT + mAlldayHeight; 
 
// offset canvas by the current drag and header position 
 
canvas.translate(-mViewStartX, yTranslate); 
 
// clip to everything below the allDay area 
 
Rect dest = mDestRect; 
 
dest.top = (int) (mFirstCell - yTranslate); 
 
dest.bottom = (int) (mViewHeight - yTranslate); 
 
dest.left = 0; 
 
dest.right = mViewWidth; 
 
canvas.save(); 
 
canvas.clipRect(dest); 
 
// Draw the movable part of the view 
 
doDraw(canvas);

 

其中canvas.translate(-mViewStartX, yTranslate)可以实现view的平移。

 

手势处理我们先进入捕获触摸事件的onTouchEvent函数:

 

onScroll()

onScroll函数不多,我就直接将整个函数贴出来了:

 

@Override 
 
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { 
 
    if (DEBUG) Log.e(TAG, "GestureDetector.onScroll"); 
 
    if (mTouchStartedInAlldayArea) { 
 
        if (Math.abs(distanceX) < Math.abs(distanceY)) { 
 
            return false; 
 
        } 
 
        // don't scroll vertically if this started in the allday area 
 
        distanceY = 0; 
 
    } 
 
              Log.i("scroll", "DayView::onScroll:distanceX="+distanceX+"and distanceY="+distanceY); 
 
    DayView.this.doScroll(e1, e2, distanceX, distanceY); 
 
    return true; 
 
}

 

onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)有四个参数,这里其实只用了后面两个distanceX,distanceY,字面意思上分别指水平和垂直滚动的距离。

根据我的log信息来看,当我手指向左的时候distanceX为正,手指向右的时候distanceX为负。手指向上的时候distanceY为正,手指向下的时候distanceY为负。

收藏 赞 (1) 踩 (3)
上一篇:Android中自定义View时MeasureSpec的作用
有时,Android系统控件无法满足我们的需求,因此有必要自定义View。具体方法参见官方开发文档: http://developer.android.com/guide/topics/ui/custom-components.html 一般来说,自定义控件都会去重写View的onMeasure方法,因为该方法指定该控件在屏幕上的
下一篇:Android实现多页左右滑动效果,支持子view动态创建和cache
要实现多页滑动效果,主要是需要处理 onTouchEvent 和 onInterceptTouchEvent ,要处理好 touch 事件的子控件和父控件的传递问题。滚动控制可以利用 android 的 Scroller 来实现。 对于不清楚 android Touch 事件的传递过程的,先 google 一下。 这里提供两