22
22
import android .view .GestureDetector ;
23
23
import android .view .HapticFeedbackConstants ;
24
24
import android .view .MotionEvent ;
25
+ import android .view .ScaleGestureDetector ;
25
26
import android .view .SoundEffectConstants ;
26
27
import android .view .View ;
27
28
import android .widget .OverScroller ;
@@ -80,6 +81,10 @@ public class WeekView extends View {
80
81
81
82
// Attributes and their default values.
82
83
private int mHourHeight = 50 ;
84
+ private int mNewHourHeight = -1 ;
85
+ private int mMinHourHeight = 0 ; //no minimum specified (will be dynamic, based on screen)
86
+ private int mEffectiveMinHourHeight = mMinHourHeight ; //compensates for the fact that you can't keep zooming out.
87
+ private int mMaxHourHeight = 250 ;
83
88
private int mColumnGap = 10 ;
84
89
private int mFirstDayOfWeek = Calendar .MONDAY ;
85
90
private int mTextSize = 12 ;
@@ -115,6 +120,8 @@ public class WeekView extends View {
115
120
private Calendar mLastVisibleDay ;
116
121
private Calendar mScrollToDay = null ;
117
122
private double mScrollToHour = -1 ;
123
+ private ScaleGestureDetector mScaleDetector ;
124
+ private boolean mIsZooming ;
118
125
119
126
// Listeners.
120
127
private EventClickListener mEventClickListener ;
@@ -136,6 +143,8 @@ public boolean onDown(MotionEvent e) {
136
143
137
144
@ Override
138
145
public boolean onScroll (MotionEvent e1 , MotionEvent e2 , float distanceX , float distanceY ) {
146
+ if (mIsZooming )
147
+ return true ;
139
148
if (mCurrentScrollDirection == Direction .NONE ) {
140
149
if (Math .abs (distanceX ) > Math .abs (distanceY )){
141
150
mCurrentScrollDirection = Direction .HORIZONTAL ;
@@ -245,6 +254,9 @@ public WeekView(Context context, AttributeSet attrs, int defStyleAttr) {
245
254
try {
246
255
mFirstDayOfWeek = a .getInteger (R .styleable .WeekView_firstDayOfWeek , mFirstDayOfWeek );
247
256
mHourHeight = a .getDimensionPixelSize (R .styleable .WeekView_hourHeight , mHourHeight );
257
+ mMinHourHeight = a .getDimensionPixelSize (R .styleable .WeekView_minHourHeight , mMinHourHeight );
258
+ mEffectiveMinHourHeight = mMinHourHeight ;
259
+ mMaxHourHeight = a .getDimensionPixelSize (R .styleable .WeekView_maxHourHeight , mMaxHourHeight );
248
260
mTextSize = a .getDimensionPixelSize (R .styleable .WeekView_textSize , (int ) TypedValue .applyDimension (TypedValue .COMPLEX_UNIT_SP , mTextSize , context .getResources ().getDisplayMetrics ()));
249
261
mHeaderColumnPadding = a .getDimensionPixelSize (R .styleable .WeekView_headerColumnPadding , mHeaderColumnPadding );
250
262
mColumnGap = a .getDimensionPixelSize (R .styleable .WeekView_columnGap , mColumnGap );
@@ -359,6 +371,33 @@ private void init() {
359
371
360
372
// Set default event color.
361
373
mDefaultEventColor = Color .parseColor ("#9fc6e7" );
374
+
375
+ mScaleDetector = new ScaleGestureDetector (mContext , new ScaleGestureDetector .OnScaleGestureListener () {
376
+ @ Override
377
+ public void onScaleEnd (ScaleGestureDetector detector ) {
378
+ mIsZooming = false ;
379
+ }
380
+
381
+ @ Override
382
+ public boolean onScaleBegin (ScaleGestureDetector detector ) {
383
+ mIsZooming = true ;
384
+ mScroller .forceFinished (true );
385
+ mCurrentScrollDirection = mCurrentFlingDirection = Direction .NONE ;
386
+ goToNearestOrigin ();
387
+ return true ;
388
+ }
389
+
390
+ @ Override
391
+ public boolean onScale (ScaleGestureDetector detector ) {
392
+ mNewHourHeight = Math .round (mHourHeight * detector .getScaleFactor ());
393
+ if (mNewHourHeight < mEffectiveMinHourHeight )
394
+ mNewHourHeight = mEffectiveMinHourHeight ;
395
+ else if (mNewHourHeight > mMaxHourHeight )
396
+ mNewHourHeight = mMaxHourHeight ;
397
+ invalidate ();
398
+ return true ;
399
+ }
400
+ });
362
401
}
363
402
364
403
/**
@@ -387,13 +426,6 @@ protected void onDraw(Canvas canvas) {
387
426
}
388
427
389
428
private void drawTimeColumnAndAxes (Canvas canvas ) {
390
- // Do not let the view go above/below the limit due to scrolling. Set the max and min limit of the scroll.
391
- if (mCurrentScrollDirection == Direction .VERTICAL ) {
392
- if (mCurrentOrigin .y - mDistanceY > 0 ) mCurrentOrigin .y = 0 ;
393
- else if (mCurrentOrigin .y - mDistanceY < -(mHourHeight * 24 + mHeaderTextHeight + mHeaderRowPadding * 2 - getHeight ())) mCurrentOrigin .y = -(mHourHeight * 24 + mHeaderTextHeight + mHeaderRowPadding * 2 - getHeight ());
394
- else mCurrentOrigin .y -= mDistanceY ;
395
- }
396
-
397
429
// Draw the background color for the header column.
398
430
canvas .drawRect (0 , mHeaderTextHeight + mHeaderRowPadding * 2 , mHeaderColumnWidth , getHeight (), mHeaderColumnBackgroundPaint );
399
431
@@ -418,8 +450,9 @@ private void drawHeaderRowAndEvents(Canvas canvas) {
418
450
419
451
if (mAreDimensionsInvalid ) {
420
452
mAreDimensionsInvalid = false ;
421
- double scrollToHour = mScrollToHour ;
453
+ mEffectiveMinHourHeight = Math . max ( mMinHourHeight , ( int ) (( getHeight () - mHeaderTextHeight - mHeaderRowPadding * 2 - mHeaderMarginBottom ) / 24 )) ;
422
454
455
+ double scrollToHour = mScrollToHour ;
423
456
if (mScrollToDay != null )
424
457
goToDate (mScrollToDay );
425
458
if (scrollToHour >= 0 )
@@ -435,6 +468,25 @@ private void drawHeaderRowAndEvents(Canvas canvas) {
435
468
}
436
469
}
437
470
471
+ // Do not let the view go above/below the limit due to scrolling. Set the max and min limit of the scroll.
472
+ if (mCurrentScrollDirection == Direction .VERTICAL )
473
+ mCurrentOrigin .y -= mDistanceY ;
474
+
475
+
476
+ //Calculate the new height due to the zooming.
477
+ if (mNewHourHeight > 0 ){
478
+ mCurrentOrigin .y = (mCurrentOrigin .y /mHourHeight )*mNewHourHeight ;
479
+ mHourHeight = mNewHourHeight ;
480
+ mNewHourHeight = -1 ;
481
+ }
482
+
483
+ //if the new mCurrentOrigin.y is invalid, make it valid.
484
+ if (mCurrentOrigin .y < getHeight () - mHourHeight * 24 - mHeaderTextHeight - mHeaderRowPadding * 2 - mHeaderMarginBottom )
485
+ mCurrentOrigin .y = getHeight () - mHourHeight * 24 - mHeaderTextHeight - mHeaderRowPadding * 2 - mHeaderMarginBottom ;
486
+ //Don't put an else if because it will trigger a glitch when completly zoomed out and scrolling vertically.
487
+ if (mCurrentOrigin .y > 0 )
488
+ mCurrentOrigin .y = 0 ;
489
+
438
490
// Consider scroll offset.
439
491
if (mCurrentScrollDirection == Direction .HORIZONTAL ) mCurrentOrigin .x -= mDistanceX ;
440
492
int leftDaysWithGaps = (int ) -(Math .ceil (mCurrentOrigin .x / (mWidthPerDay + mColumnGap )));
@@ -1390,23 +1442,29 @@ public void setXScrollingSpeed(float xScrollingSpeed) {
1390
1442
1391
1443
@ Override
1392
1444
public boolean onTouchEvent (MotionEvent event ) {
1393
- if (event .getAction () == MotionEvent .ACTION_UP ) {
1394
-
1445
+ if (event .getAction () == MotionEvent .ACTION_UP && !mIsZooming ) {
1395
1446
if (mCurrentScrollDirection == Direction .HORIZONTAL ) {
1396
- float leftDays = Math .round (mCurrentOrigin .x / (mWidthPerDay + mColumnGap ));
1397
- if (mDistanceX > 0 )
1398
- leftDays --;
1399
- else
1400
- leftDays ++;
1401
- int nearestOrigin = (int ) (mCurrentOrigin .x - leftDays * (mWidthPerDay +mColumnGap ));
1402
- mStickyScroller .startScroll ((int ) mCurrentOrigin .x , 0 , - nearestOrigin , 0 );
1403
- ViewCompat .postInvalidateOnAnimation (WeekView .this );
1447
+ goToNearestOrigin ();
1404
1448
}
1405
1449
mCurrentScrollDirection = Direction .NONE ;
1406
1450
}
1451
+ mScaleDetector .onTouchEvent (event );
1407
1452
return mGestureDetector .onTouchEvent (event );
1408
1453
}
1409
1454
1455
+ private void goToNearestOrigin (){
1456
+ float leftDays = Math .round (mCurrentOrigin .x / (mWidthPerDay + mColumnGap ));
1457
+ if (!mIsZooming ){
1458
+ if (mDistanceX > 0 )
1459
+ leftDays --;
1460
+ else
1461
+ leftDays ++;
1462
+ }
1463
+ int nearestOrigin = (int ) (mCurrentOrigin .x - leftDays * (mWidthPerDay +mColumnGap ));
1464
+ mStickyScroller .startScroll ((int ) mCurrentOrigin .x , 0 , - nearestOrigin , 0 );
1465
+ ViewCompat .postInvalidateOnAnimation (WeekView .this );
1466
+ }
1467
+
1410
1468
1411
1469
@ Override
1412
1470
public void computeScroll () {
0 commit comments