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,6 +450,7 @@ private void drawHeaderRowAndEvents(Canvas canvas) {
418
450
419
451
if (mAreDimensionsInvalid ) {
420
452
mAreDimensionsInvalid = false ;
453
+ mEffectiveMinHourHeight = Math .max (mMinHourHeight , (int ) ((getHeight () - mHeaderTextHeight - mHeaderRowPadding * 2 - mHeaderMarginBottom ) / 24 ));
421
454
422
455
if (mScrollToDay != null )
423
456
goToDate (mScrollToDay );
@@ -434,6 +467,25 @@ private void drawHeaderRowAndEvents(Canvas canvas) {
434
467
}
435
468
}
436
469
470
+ // Do not let the view go above/below the limit due to scrolling. Set the max and min limit of the scroll.
471
+ if (mCurrentScrollDirection == Direction .VERTICAL )
472
+ mCurrentOrigin .y -= mDistanceY ;
473
+
474
+
475
+ //Calculate the new height due to the zooming.
476
+ if (mNewHourHeight > 0 ){
477
+ mCurrentOrigin .y = (mCurrentOrigin .y /mHourHeight )*mNewHourHeight ;
478
+ mHourHeight = mNewHourHeight ;
479
+ mNewHourHeight = -1 ;
480
+ }
481
+
482
+ //if the new mCurrentOrigin.y is invalid, make it valid.
483
+ if (mCurrentOrigin .y < getHeight () - mHourHeight * 24 - mHeaderTextHeight - mHeaderRowPadding * 2 - mHeaderMarginBottom )
484
+ mCurrentOrigin .y = getHeight () - mHourHeight * 24 - mHeaderTextHeight - mHeaderRowPadding * 2 - mHeaderMarginBottom ;
485
+ //Don't put an else if because it will trigger a glitch when completly zoomed out and scrolling vertically.
486
+ if (mCurrentOrigin .y > 0 )
487
+ mCurrentOrigin .y = 0 ;
488
+
437
489
// Consider scroll offset.
438
490
if (mCurrentScrollDirection == Direction .HORIZONTAL ) mCurrentOrigin .x -= mDistanceX ;
439
491
int leftDaysWithGaps = (int ) -(Math .ceil (mCurrentOrigin .x / (mWidthPerDay + mColumnGap )));
@@ -1389,23 +1441,29 @@ public void setXScrollingSpeed(float xScrollingSpeed) {
1389
1441
1390
1442
@ Override
1391
1443
public boolean onTouchEvent (MotionEvent event ) {
1392
- if (event .getAction () == MotionEvent .ACTION_UP ) {
1393
-
1444
+ if (event .getAction () == MotionEvent .ACTION_UP && !mIsZooming ) {
1394
1445
if (mCurrentScrollDirection == Direction .HORIZONTAL ) {
1395
- float leftDays = Math .round (mCurrentOrigin .x / (mWidthPerDay + mColumnGap ));
1396
- if (mDistanceX > 0 )
1397
- leftDays --;
1398
- else
1399
- leftDays ++;
1400
- int nearestOrigin = (int ) (mCurrentOrigin .x - leftDays * (mWidthPerDay +mColumnGap ));
1401
- mStickyScroller .startScroll ((int ) mCurrentOrigin .x , 0 , - nearestOrigin , 0 );
1402
- ViewCompat .postInvalidateOnAnimation (WeekView .this );
1446
+ goToNearestOrigin ();
1403
1447
}
1404
1448
mCurrentScrollDirection = Direction .NONE ;
1405
1449
}
1450
+ mScaleDetector .onTouchEvent (event );
1406
1451
return mGestureDetector .onTouchEvent (event );
1407
1452
}
1408
1453
1454
+ private void goToNearestOrigin (){
1455
+ float leftDays = Math .round (mCurrentOrigin .x / (mWidthPerDay + mColumnGap ));
1456
+ if (!mIsZooming ){
1457
+ if (mDistanceX > 0 )
1458
+ leftDays --;
1459
+ else
1460
+ leftDays ++;
1461
+ }
1462
+ int nearestOrigin = (int ) (mCurrentOrigin .x - leftDays * (mWidthPerDay +mColumnGap ));
1463
+ mStickyScroller .startScroll ((int ) mCurrentOrigin .x , 0 , - nearestOrigin , 0 );
1464
+ ViewCompat .postInvalidateOnAnimation (WeekView .this );
1465
+ }
1466
+
1409
1467
1410
1468
@ Override
1411
1469
public void computeScroll () {
0 commit comments