Skip to content

Commit e1138e0

Browse files
committed
Merge remote-tracking branch 'refs/remotes/origin/develop'
2 parents 616454f + 56b9d40 commit e1138e0

File tree

6 files changed

+122
-44
lines changed

6 files changed

+122
-44
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,12 @@ To do
155155
Changelog
156156
---------
157157

158+
**Version 1.2.5**
159+
160+
* Add support for subclasses of `WeekViewEvent`
161+
* Fix scroll animation
162+
* Add support for semi-transparent header colors
163+
158164
**Version 1.2.4**
159165

160166
* **NOTE:** If you are using `WeekView.MonthChangeListener`, make sure to change it into `MonthLoader.MonthChangeListener`

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
VERSION_NAME=1.2.4
1+
VERSION_NAME=1.2.5
22
GROUP=com.github.alamkanak
33

44
POM_DESCRIPTION=An android library to show day view, week view, 3 day view etc. in your app.

library/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ android {
1515
}
1616

1717
dependencies {
18-
compile 'com.android.support:appcompat-v7:23.0.1'
18+
compile 'com.android.support:appcompat-v7:23.1.1'
1919
}
2020

2121
apply from: 'https://raw.github.com/chrisbanes/gradle-mvn-push/master/gradle-mvn-push.gradle'

library/src/main/java/com/alamkanak/weekview/MonthLoader.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public double toWeekViewPeriodIndex(Calendar instance){
1717
}
1818

1919
@Override
20-
public List<WeekViewEvent> onLoad(int periodIndex){
20+
public List<? extends WeekViewEvent> onLoad(int periodIndex){
2121
return mOnMonthChangeListener.onMonthChange(periodIndex / 12, periodIndex % 12 + 1);
2222
}
2323

@@ -34,10 +34,10 @@ public interface MonthChangeListener {
3434
* Very important interface, it's the base to load events in the calendar.
3535
* This method is called three times: once to load the previous month, once to load the next month and once to load the current month.<br/>
3636
* <strong>That's why you can have three times the same event at the same place if you mess up with the configuration</strong>
37-
* @param newYear: year of the events required by the view.
38-
* @param newMonth: month of the events required by the view <br/><strong>1 based (not like JAVA API) --> January = 1 and December = 12</strong>.
37+
* @param newYear : year of the events required by the view.
38+
* @param newMonth : month of the events required by the view <br/><strong>1 based (not like JAVA API) --> January = 1 and December = 12</strong>.
3939
* @return a list of the events happening <strong>during the specified month</strong>.
4040
*/
41-
List<WeekViewEvent> onMonthChange(int newYear, int newMonth);
41+
List<? extends WeekViewEvent> onMonthChange(int newYear, int newMonth);
4242
}
4343
}

library/src/main/java/com/alamkanak/weekview/WeekView.java

Lines changed: 109 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@
88
import android.graphics.PointF;
99
import android.graphics.Rect;
1010
import android.graphics.RectF;
11+
import android.graphics.Region;
1112
import android.graphics.Typeface;
13+
import android.os.Build;
1214
import android.support.annotation.Nullable;
1315
import android.support.v4.view.GestureDetectorCompat;
1416
import android.support.v4.view.ViewCompat;
17+
import android.support.v4.view.animation.FastOutLinearInInterpolator;
1518
import android.text.Layout;
1619
import android.text.SpannableStringBuilder;
1720
import android.text.StaticLayout;
@@ -27,6 +30,7 @@
2730
import android.view.ScaleGestureDetector;
2831
import android.view.SoundEffectConstants;
2932
import android.view.View;
33+
import android.view.ViewConfiguration;
3034
import android.widget.OverScroller;
3135

3236
import java.text.SimpleDateFormat;
@@ -43,6 +47,10 @@
4347
*/
4448
public class WeekView extends View {
4549

50+
private enum Direction {
51+
NONE, LEFT, RIGHT, VERTICAL
52+
}
53+
4654
@Deprecated
4755
public static final int LENGTH_SHORT = 1;
4856
@Deprecated
@@ -72,9 +80,9 @@ public class WeekView extends View {
7280
private Paint mEventBackgroundPaint;
7381
private float mHeaderColumnWidth;
7482
private List<EventRect> mEventRects;
75-
private List<WeekViewEvent> mPreviousPeriodEvents;
76-
private List<WeekViewEvent> mCurrentPeriodEvents;
77-
private List<WeekViewEvent> mNextPeriodEvents;
83+
private List<? extends WeekViewEvent> mPreviousPeriodEvents;
84+
private List<? extends WeekViewEvent> mCurrentPeriodEvents;
85+
private List<? extends WeekViewEvent> mNextPeriodEvents;
7886
private TextPaint mEventTextPaint;
7987
private Paint mHeaderColumnBackgroundPaint;
8088
private int mFetchedPeriod = -1; // the middle period the calendar has fetched.
@@ -85,7 +93,8 @@ public class WeekView extends View {
8593
private Calendar mFirstVisibleDay;
8694
private Calendar mLastVisibleDay;
8795
private int mDefaultEventColor;
88-
96+
private int mMinimumFlingVelocity = 0;
97+
private int mScaledTouchSlop = 0;
8998
// Attributes and their default values.
9099
private int mHourHeight = 50;
91100
private int mNewHourHeight = -1;
@@ -151,20 +160,40 @@ public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float d
151160
if (mIsZooming)
152161
return true;
153162

154-
// Calculate the direction to scroll.
155-
if (mCurrentScrollDirection == Direction.NONE) {
156-
// allow scrolling only in one direction
157-
if (Math.abs(distanceX) > Math.abs(distanceY)){
158-
mCurrentScrollDirection = Direction.HORIZONTAL;
163+
switch (mCurrentScrollDirection) {
164+
case NONE: {
165+
// Allow scrolling only in one direction.
166+
if (Math.abs(distanceX) > Math.abs(distanceY)) {
167+
if (distanceX > 0) {
168+
mCurrentScrollDirection = Direction.LEFT;
169+
} else {
170+
mCurrentScrollDirection = Direction.RIGHT;
171+
}
172+
} else {
173+
mCurrentScrollDirection = Direction.VERTICAL;
174+
}
175+
break;
159176
}
160-
else {
161-
mCurrentScrollDirection = Direction.VERTICAL;
177+
case LEFT: {
178+
// Change direction if there was enough change.
179+
if (Math.abs(distanceX) > Math.abs(distanceY) && (distanceX < -mScaledTouchSlop)) {
180+
mCurrentScrollDirection = Direction.RIGHT;
181+
}
182+
break;
183+
}
184+
case RIGHT: {
185+
// Change direction if there was enough change.
186+
if (Math.abs(distanceX) > Math.abs(distanceY) && (distanceX > mScaledTouchSlop)) {
187+
mCurrentScrollDirection = Direction.LEFT;
188+
}
189+
break;
162190
}
163191
}
164192

165193
// Calculate the new origin after scroll.
166194
switch (mCurrentScrollDirection) {
167-
case HORIZONTAL:
195+
case LEFT:
196+
case RIGHT:
168197
mCurrentOrigin.x -= distanceX * mXScrollingSpeed;
169198
ViewCompat.postInvalidateOnAnimation(WeekView.this);
170199
break;
@@ -178,14 +207,20 @@ public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float d
178207

179208
@Override
180209
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
210+
if (mIsZooming)
211+
return true;
212+
181213
mScroller.forceFinished(true);
182214

183215
mCurrentFlingDirection = mCurrentScrollDirection;
184-
if (mCurrentFlingDirection == Direction.HORIZONTAL){
185-
mScroller.fling((int) mCurrentOrigin.x, (int) mCurrentOrigin.y, (int) (velocityX * mXScrollingSpeed), 0, Integer.MIN_VALUE, Integer.MAX_VALUE, (int) -(mHourHeight * 24 + mHeaderTextHeight + mHeaderRowPadding * 2 + mHeaderMarginBottom + mTimeTextHeight/2 - getHeight()), 0);
186-
}
187-
else if (mCurrentFlingDirection == Direction.VERTICAL){
188-
mScroller.fling((int) mCurrentOrigin.x, (int) mCurrentOrigin.y, 0, (int) velocityY, Integer.MIN_VALUE, Integer.MAX_VALUE, (int) -(mHourHeight * 24 + mHeaderTextHeight + mHeaderRowPadding * 2 + mHeaderMarginBottom + mTimeTextHeight/2 - getHeight()), 0);
216+
switch (mCurrentFlingDirection) {
217+
case LEFT:
218+
case RIGHT:
219+
mScroller.fling((int) mCurrentOrigin.x, (int) mCurrentOrigin.y, (int) (velocityX * mXScrollingSpeed), 0, Integer.MIN_VALUE, Integer.MAX_VALUE, (int) -(mHourHeight * 24 + mHeaderTextHeight + mHeaderRowPadding * 2 + mHeaderMarginBottom + mTimeTextHeight / 2 - getHeight()), 0);
220+
break;
221+
case VERTICAL:
222+
mScroller.fling((int) mCurrentOrigin.x, (int) mCurrentOrigin.y, 0, (int) velocityY, Integer.MIN_VALUE, Integer.MAX_VALUE, (int) -(mHourHeight * 24 + mHeaderTextHeight + mHeaderRowPadding * 2 + mHeaderMarginBottom + mTimeTextHeight/2 - getHeight()), 0);
223+
break;
189224
}
190225

191226
ViewCompat.postInvalidateOnAnimation(WeekView.this);
@@ -247,10 +282,6 @@ public void onLongPress(MotionEvent e) {
247282
}
248283
};
249284

250-
private enum Direction {
251-
NONE, HORIZONTAL, VERTICAL
252-
}
253-
254285
public WeekView(Context context) {
255286
this(context, null);
256287
}
@@ -314,7 +345,10 @@ public WeekView(Context context, AttributeSet attrs, int defStyleAttr) {
314345
private void init() {
315346
// Scrolling initialization.
316347
mGestureDetector = new GestureDetectorCompat(mContext, mGestureListener);
317-
mScroller = new OverScroller(mContext);
348+
mScroller = new OverScroller(mContext, new FastOutLinearInInterpolator());
349+
350+
mMinimumFlingVelocity = ViewConfiguration.get(mContext).getScaledMinimumFlingVelocity();
351+
mScaledTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
318352

319353
// Measure settings for time column.
320354
mTimeTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@@ -438,23 +472,23 @@ private void initTextTimeWidth() {
438472
protected void onDraw(Canvas canvas) {
439473
super.onDraw(canvas);
440474

475+
// Hide everything in the first cell (top left corner).
476+
canvas.drawRect(0, 0, mTimeTextWidth + mHeaderColumnPadding * 2, mHeaderTextHeight + mHeaderRowPadding * 2, mHeaderBackgroundPaint);
477+
441478
// Draw the header row.
442479
drawHeaderRowAndEvents(canvas);
443480

444481
// Draw the time column and all the axes/separators.
445482
drawTimeColumnAndAxes(canvas);
446-
447-
// Hide everything in the first cell (top left corner).
448-
canvas.drawRect(0, 0, mTimeTextWidth + mHeaderColumnPadding * 2, mHeaderTextHeight + mHeaderRowPadding * 2, mHeaderBackgroundPaint);
449-
450-
// Hide anything that is in the bottom margin of the header row.
451-
canvas.drawRect(mHeaderColumnWidth, mHeaderTextHeight + mHeaderRowPadding * 2, getWidth(), mHeaderRowPadding * 2 + mHeaderTextHeight + mHeaderMarginBottom + mTimeTextHeight/2, mHeaderColumnBackgroundPaint);
452483
}
453484

454485
private void drawTimeColumnAndAxes(Canvas canvas) {
455486
// Draw the background color for the header column.
456487
canvas.drawRect(0, mHeaderTextHeight + mHeaderRowPadding * 2, mHeaderColumnWidth, getHeight(), mHeaderColumnBackgroundPaint);
457488

489+
// Clip to paint in left column only.
490+
canvas.clipRect(0, mHeaderTextHeight + mHeaderRowPadding * 2, mHeaderColumnWidth, getHeight(), Region.Op.REPLACE);
491+
458492
for (int i = 0; i < 24; i++) {
459493
float top = mHeaderTextHeight + mHeaderRowPadding * 2 + mCurrentOrigin.y + mHourHeight * i + mHeaderMarginBottom;
460494

@@ -544,6 +578,9 @@ else if (mNewHourHeight > mMaxHourHeight)
544578
}
545579
}
546580

581+
// Clip to paint events only.
582+
canvas.clipRect(mHeaderColumnWidth, mHeaderTextHeight + mHeaderRowPadding * 2 + mHeaderMarginBottom + mTimeTextHeight/2, getWidth(), getHeight(), Region.Op.REPLACE);
583+
547584
// Iterate through each day.
548585
Calendar oldFirstVisibleDay = mFirstVisibleDay;
549586
mFirstVisibleDay = (Calendar) today.clone();
@@ -629,6 +666,10 @@ else if (day.before(today)) {
629666
startPixel += mWidthPerDay + mColumnGap;
630667
}
631668

669+
670+
// Clip to paint header row only.
671+
canvas.clipRect(mHeaderColumnWidth, 0, getWidth(), mHeaderTextHeight + mHeaderRowPadding * 2, Region.Op.REPLACE);
672+
632673
// Draw the header background.
633674
canvas.drawRect(0, 0, getWidth(), mHeaderTextHeight + mHeaderRowPadding * 2, mHeaderBackgroundPaint);
634675

@@ -845,9 +886,9 @@ private void getMoreEvents(Calendar day) {
845886
if (mWeekViewLoader != null){
846887
int periodToFetch = (int) mWeekViewLoader.toWeekViewPeriodIndex(day);
847888
if (!isInEditMode() && (mFetchedPeriod < 0 || mFetchedPeriod != periodToFetch || mRefreshEvents)) {
848-
List<WeekViewEvent> previousPeriodEvents = null;
849-
List<WeekViewEvent> currentPeriodEvents = null;
850-
List<WeekViewEvent> nextPeriodEvents = null;
889+
List<? extends WeekViewEvent> previousPeriodEvents = null;
890+
List<? extends WeekViewEvent> currentPeriodEvents = null;
891+
List<? extends WeekViewEvent> nextPeriodEvents = null;
851892

852893
if (mPreviousPeriodEvents != null && mCurrentPeriodEvents != null && mNextPeriodEvents != null){
853894
if (periodToFetch == mFetchedPeriod-1){
@@ -917,6 +958,8 @@ else if (periodToFetch == mFetchedPeriod+1){
917958
* @param event The event to cache.
918959
*/
919960
private void cacheEvent(WeekViewEvent event) {
961+
if(event.getStartTime().compareTo(event.getEndTime()) >= 0)
962+
return;
920963
if (!isSameDay(event.getStartTime(), event.getEndTime())) {
921964
// Add first day.
922965
Calendar endTime = (Calendar) event.getStartTime().clone();
@@ -961,7 +1004,7 @@ private void cacheEvent(WeekViewEvent event) {
9611004
* Sort and cache events.
9621005
* @param events The events to be sorted and cached.
9631006
*/
964-
private void sortAndCacheEvents(List<WeekViewEvent> events) {
1007+
private void sortAndCacheEvents(List<? extends WeekViewEvent> events) {
9651008
sortEvents(events);
9661009
for (WeekViewEvent event : events) {
9671010
cacheEvent(event);
@@ -972,7 +1015,7 @@ private void sortAndCacheEvents(List<WeekViewEvent> events) {
9721015
* Sorts the events in ascending order.
9731016
* @param events The events to be sorted.
9741017
*/
975-
private void sortEvents(List<WeekViewEvent> events) {
1018+
private void sortEvents(List<? extends WeekViewEvent> events) {
9761019
Collections.sort(events, new Comparator<WeekViewEvent>() {
9771020
@Override
9781021
public int compare(WeekViewEvent event1, WeekViewEvent event2) {
@@ -1636,7 +1679,7 @@ public boolean onTouchEvent(MotionEvent event) {
16361679

16371680
// Check after call of mGestureDetector, so mCurrentFlingDirection and mCurrentScrollDirection are set.
16381681
if (event.getAction() == MotionEvent.ACTION_UP && !mIsZooming && mCurrentFlingDirection == Direction.NONE) {
1639-
if (mCurrentScrollDirection == Direction.HORIZONTAL) {
1682+
if (mCurrentScrollDirection == Direction.RIGHT || mCurrentScrollDirection == Direction.LEFT) {
16401683
goToNearestOrigin();
16411684
}
16421685
mCurrentScrollDirection = Direction.NONE;
@@ -1646,15 +1689,29 @@ public boolean onTouchEvent(MotionEvent event) {
16461689
}
16471690

16481691
private void goToNearestOrigin(){
1649-
float leftDays = Math.round(mCurrentOrigin.x / (mWidthPerDay + mColumnGap));
1692+
double leftDays = mCurrentOrigin.x / (mWidthPerDay + mColumnGap);
1693+
1694+
if (mCurrentFlingDirection != Direction.NONE) {
1695+
// snap to nearest day
1696+
leftDays = Math.round(leftDays);
1697+
} else if (mCurrentScrollDirection == Direction.LEFT) {
1698+
// snap to last day
1699+
leftDays = Math.floor(leftDays);
1700+
} else if (mCurrentScrollDirection == Direction.RIGHT) {
1701+
// snap to next day
1702+
leftDays = Math.ceil(leftDays);
1703+
} else {
1704+
// snap to nearest day
1705+
leftDays = Math.round(leftDays);
1706+
}
16501707

16511708
int nearestOrigin = (int) (mCurrentOrigin.x - leftDays * (mWidthPerDay + mColumnGap));
16521709

16531710
if (nearestOrigin != 0) {
16541711
// Stop current animation.
16551712
mScroller.forceFinished(true);
16561713
// Snap to date.
1657-
mScroller.startScroll((int) mCurrentOrigin.x, (int) mCurrentOrigin.y, -nearestOrigin, 0, 50);
1714+
mScroller.startScroll((int) mCurrentOrigin.x, (int) mCurrentOrigin.y, -nearestOrigin, 0, (int) (Math.abs(nearestOrigin) / mWidthPerDay * 500));
16581715
ViewCompat.postInvalidateOnAnimation(WeekView.this);
16591716
}
16601717
// Reset scrolling and fling direction.
@@ -1672,14 +1729,29 @@ public void computeScroll() {
16721729
goToNearestOrigin();
16731730
}
16741731
} else {
1675-
if (mScroller.computeScrollOffset()) {
1732+
if (mCurrentFlingDirection != Direction.NONE && forceFinishScroll()) {
1733+
goToNearestOrigin();
1734+
} else if (mScroller.computeScrollOffset()) {
16761735
mCurrentOrigin.y = mScroller.getCurrY();
16771736
mCurrentOrigin.x = mScroller.getCurrX();
16781737
ViewCompat.postInvalidateOnAnimation(this);
16791738
}
16801739
}
16811740
}
16821741

1742+
/**
1743+
* Check if scrolling should be stopped.
1744+
* @return true if scrolling should be stopped before reaching the end of animation.
1745+
*/
1746+
private boolean forceFinishScroll() {
1747+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
1748+
// current velocity only available since api 14
1749+
return mScroller.getCurrVelocity() <= mMinimumFlingVelocity;
1750+
} else {
1751+
return false;
1752+
}
1753+
}
1754+
16831755

16841756
/////////////////////////////////////////////////////////////////
16851757
//

library/src/main/java/com/alamkanak/weekview/WeekViewLoader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@ public interface WeekViewLoader {
2020
* @param periodIndex the period to load
2121
* @return A list with the events of this period
2222
*/
23-
List<WeekViewEvent> onLoad(int periodIndex);
23+
List<? extends WeekViewEvent> onLoad(int periodIndex);
2424
}

0 commit comments

Comments
 (0)