diff --git a/README.md b/README.md index 84af91d82..03669b973 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,8 @@ You can customize the look of the `WeekView` in xml. Use the following attribute - `eventTextColor` - `eventTextSize` - `firstDayOfWeek` +- `zoomFocusPoint` The focused point (percentage of the view height) where the week view is zoomed around. This point will not move while zooming. You can declare it as a fraction `app:focusPoint="30%"` and if is not declared the top of the view is used. +- `zoomFocusPointEnabled` If you set this to ``false`` the zoomFocusPoint won't take effect any more while zooming. The zoom will always be focused at the center of your gesture. - `headerColumnBackground` - `headerColumnPadding` - `headerColumnTextColor` diff --git a/library/src/main/java/com/alamkanak/weekview/WeekView.java b/library/src/main/java/com/alamkanak/weekview/WeekView.java index da3fa71a0..fd3437508 100755 --- a/library/src/main/java/com/alamkanak/weekview/WeekView.java +++ b/library/src/main/java/com/alamkanak/weekview/WeekView.java @@ -142,7 +142,9 @@ private enum Direction { private boolean mShowDistinctPastFutureColor = false; private boolean mHorizontalFlingEnabled = true; private boolean mVerticalFlingEnabled = true; - private int mAllDayEventHeight = 100; + private int mAllDayEventHeight= 100; + private float mZoomFocusPoint = 0; + private boolean mZoomFocusPointEnabled = true; private int mScrollDuration = 250; // Listeners. @@ -352,6 +354,8 @@ public WeekView(Context context, AttributeSet attrs, int defStyleAttr) { mHorizontalFlingEnabled = a.getBoolean(R.styleable.WeekView_horizontalFlingEnabled, mHorizontalFlingEnabled); mVerticalFlingEnabled = a.getBoolean(R.styleable.WeekView_verticalFlingEnabled, mVerticalFlingEnabled); mAllDayEventHeight = a.getDimensionPixelSize(R.styleable.WeekView_allDayEventHeight, mAllDayEventHeight); + mZoomFocusPoint = a.getFraction(R.styleable.WeekView_zoomFocusPoint, 1, 1, mZoomFocusPoint); + mZoomFocusPointEnabled = a.getBoolean(R.styleable.WeekView_zoomFocusPointEnabled, mZoomFocusPointEnabled); mScrollDuration = a.getInt(R.styleable.WeekView_scrollDuration, mScrollDuration); } finally { a.recycle(); @@ -443,26 +447,7 @@ private void init() { // Set default event color. mDefaultEventColor = Color.parseColor("#9fc6e7"); - mScaleDetector = new ScaleGestureDetector(mContext, new ScaleGestureDetector.OnScaleGestureListener() { - @Override - public void onScaleEnd(ScaleGestureDetector detector) { - mIsZooming = false; - } - - @Override - public boolean onScaleBegin(ScaleGestureDetector detector) { - mIsZooming = true; - goToNearestOrigin(); - return true; - } - - @Override - public boolean onScale(ScaleGestureDetector detector) { - mNewHourHeight = Math.round(mHourHeight * detector.getScaleFactor()); - invalidate(); - return true; - } - }); + mScaleDetector = new ScaleGestureDetector(mContext, new WeekViewGestureListener()); } // fix rotation changes @@ -586,7 +571,6 @@ private void drawHeaderRowAndEvents(Canvas canvas) { else if (mNewHourHeight > mMaxHourHeight) mNewHourHeight = mMaxHourHeight; - mCurrentOrigin.y = (mCurrentOrigin.y/mHourHeight)*mNewHourHeight; mHourHeight = mNewHourHeight; mNewHourHeight = -1; } @@ -1798,6 +1782,45 @@ public void setAllDayEventHeight(int height) { mAllDayEventHeight = height; } + /** + * Enable zoom focus point + * If you set this to false the `zoomFocusPoint` won't take effect any more while zooming. + * The zoom will always be focused at the center of your gesture. + */ + public void setZoomFocusPointEnabled(boolean zoomFocusPointEnabled) { + mZoomFocusPointEnabled = zoomFocusPointEnabled; + } + + /* + * Is focus point enabled + * @return fixed focus point enabled? + */ + public boolean isZoomFocusPointEnabled() { + return mZoomFocusPointEnabled; + } + + /* + * Get focus point + * 0 = top of view, 1 = bottom of view + * The focused point (multiplier of the view height) where the week view is zoomed around. + * This point will not move while zooming. + * @return focus point + */ + public float getZoomFocusPoint() { + return mZoomFocusPoint; + } + + /** + * Set focus point + * 0 = top of view, 1 = bottom of view + * The focused point (multiplier of the view height) where the week view is zoomed around. + * This point will not move while zooming. + */ + public void setZoomFocusPoint(int zoomFocusPoint) { + mZoomFocusPoint = zoomFocusPoint; + } + + /** * Get scroll duration * @return scroll duration @@ -2039,4 +2062,52 @@ public interface ScrollListener { */ void onFirstVisibleDayChanged(Calendar newFirstVisibleDay, Calendar oldFirstVisibleDay); } + + /** + * A simple GestureListener that holds the focused hour while scaling. + */ + private class WeekViewGestureListener implements ScaleGestureDetector.OnScaleGestureListener { + + float mFocusedPointY; + + @Override + public void onScaleEnd(ScaleGestureDetector detector) { + mIsZooming = false; + } + + @Override + public boolean onScaleBegin(ScaleGestureDetector detector) { + mIsZooming = true; + goToNearestOrigin(); + + // Calculate focused point for scale action + if (mZoomFocusPointEnabled) { + // Use fractional focus, percentage of height + mFocusedPointY = (getHeight() - mHeaderHeight - mHeaderRowPadding * 2 - mHeaderMarginBottom) * mZoomFocusPoint; + } else { + // Grab focus + mFocusedPointY = detector.getFocusY(); + } + + return true; + } + + @Override + public boolean onScale(ScaleGestureDetector detector) { + final float scale = detector.getScaleFactor(); + + mNewHourHeight = Math.round(mHourHeight * scale); + + // Calculating difference + float diffY = mFocusedPointY - mCurrentOrigin.y; + // Scaling difference + diffY = diffY * scale - diffY; + // Updating week view origin + mCurrentOrigin.y -= diffY; + + invalidate(); + return true; + } + + } } diff --git a/library/src/main/res/values/attrs.xml b/library/src/main/res/values/attrs.xml index a37a3717b..affc40c92 100644 --- a/library/src/main/res/values/attrs.xml +++ b/library/src/main/res/values/attrs.xml @@ -50,6 +50,8 @@ + +