/* * Copyright (C) 2016 huanghaibin_dev * WebSite https://github.com/MiracleTimes-Dev * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.haibin.oldcalendarview; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; import android.annotation.SuppressLint; import android.content.Context; import android.content.res.TypedArray; import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.LinearLayout; /** * 日历布局 */ public class CalendarLayout extends LinearLayout { WrapViewPager mViewPager; ViewGroup mContentView; private int mTouchSlop; private int mContentViewTranslateY; //ContentView 可滑动的最大距离距离 , 固定 private int mViewPagerTranslateY = 0;// ViewPager可以平移的距离 private float downY; private float mLastY; private boolean isAnimating = false; private int mContentViewId; private VelocityTracker mVelocityTracker; private int mMaximumVelocity; public CalendarLayout(Context context, AttributeSet attrs) { super(context, attrs); setOrientation(LinearLayout.VERTICAL); TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CalendarLayout); mContentViewId = array.getResourceId(R.styleable.CalendarLayout_calendar_content_view_id, 0); array.recycle(); //setSelectPosition(6); mVelocityTracker = VelocityTracker.obtain(); final ViewConfiguration configuration = ViewConfiguration.get(context); mTouchSlop = configuration.getScaledTouchSlop(); mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); } void initCalendarPosition(Calendar cur) { java.util.Calendar date = java.util.Calendar.getInstance(); date.set(cur.getYear(), cur.getMonth() - 1, 1); int diff = date.get(java.util.Calendar.DAY_OF_WEEK) - 1;//月第一天为星期几,星期天 == 0,则偏移几天 int size = diff + cur.getDay(); setSelectPosition(size); } /** * 当前第几项被选中 */ void setSelectPosition(int selectPosition) { int line = (selectPosition + 7) / 7; mViewPagerTranslateY = (line - 1) * Util.dipToPx(getContext(), CalendarCardView.ITEM_HEIGHT); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (mContentView != null && mViewPager != null) { int h = getHeight() - Util.dipToPx(getContext(), CalendarCardView.ITEM_HEIGHT) - Util.dipToPx(getContext(), 41); int heightSpec = MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY); mContentView.measure(widthMeasureSpec, heightSpec); } } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mContentViewTranslateY = mViewPager.getMeasuredHeight() - Util.dipToPx(getContext(), CalendarCardView.ITEM_HEIGHT); } @Override protected void onFinishInflate() { super.onFinishInflate(); mViewPager = (WrapViewPager) findViewById(R.id.vp_calendar).findViewById(R.id.vp_calendar); mContentView = (ViewGroup) findViewById(mContentViewId); if (mContentView != null) { mContentView.setOverScrollMode(View.OVER_SCROLL_NEVER); } } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (isAnimating) { return true; } if (mContentView == null || mContentView.getVisibility() != VISIBLE) { return super.onInterceptTouchEvent(ev); } final int action = ev.getAction(); float y = ev.getY(); switch (action) { case MotionEvent.ACTION_DOWN: mLastY = downY = y; break; case MotionEvent.ACTION_MOVE: float dy = y - mLastY; /* 如果向上滚动,且ViewPager已经收缩,不拦截事件 */ if (dy < 0 && mContentView.getTranslationY() == -mContentViewTranslateY) { return false; } /* * 如果向下滚动,有 2 种情况处理 且y在ViewPager下方 * 1、RecyclerView 或者其它滚动的View,当mContentView滚动到顶部时,拦截事件 * 2、非滚动控件,直接拦截事件 */ if (dy > 0 && mContentView.getTranslationY() == -mContentViewTranslateY && y >= Util.dipToPx(getContext(), 98)) { if (!isScrollTop()) return false; } if (dy > 0 && mContentView.getTranslationY() == 0 && y >= Util.dipToPx(getContext(), 98)) { return false; } if (Math.abs(dy) > mTouchSlop) {//大于mTouchSlop开始拦截事件,ContentView和ViewPager得到CANCEL事件 if ((dy > 0 && mContentView.getTranslationY() <= 0) || (dy < 0 && mContentView.getTranslationY() >= -mContentViewTranslateY)) { mLastY = y; return true; } } break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: break; } return super.onInterceptTouchEvent(ev); } @SuppressLint("ClickableViewAccessibility") @Override public boolean onTouchEvent(MotionEvent event) { if (mContentView == null) return false; int action = event.getAction(); float y = event.getY(); mVelocityTracker.addMovement(event); switch (action) { case MotionEvent.ACTION_DOWN: mLastY = downY = y; return true; case MotionEvent.ACTION_MOVE: float dy = y - mLastY; if (dy < 0 && mContentView.getTranslationY() == -mContentViewTranslateY) { mContentView.onTouchEvent(event); return false; } if (dy > 0 && mContentView.getTranslationY() + dy >= 0) { mContentView.setTranslationY(0); translationViewPager(); return super.onTouchEvent(event); } if (dy < 0 && mContentView.getTranslationY() + dy <= -mContentViewTranslateY) { mContentView.setTranslationY(-mContentViewTranslateY); translationViewPager(); return super.onTouchEvent(event); } mContentView.setTranslationY(mContentView.getTranslationY() + dy); translationViewPager(); mLastY = y; break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: final VelocityTracker velocityTracker = mVelocityTracker; velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); float mYVelocity = velocityTracker.getYVelocity(); if (mContentView.getTranslationY() == 0 || mContentView.getTranslationY() == mContentViewTranslateY) { break; } if (Math.abs(mYVelocity) >= 800) { if (mYVelocity < 0) { shrink(); } else { expand(); } return super.onTouchEvent(event); } if (event.getY() - downY > 0) { expand(); } else { shrink(); } break; } return super.onTouchEvent(event); } private void translationViewPager() { float percent = mContentView.getTranslationY() * 1.0f / mContentViewTranslateY; mViewPager.setTranslationY(mViewPagerTranslateY * percent); } /** * 展开 */ public void expand() { ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mContentView, "translationY", mContentView.getTranslationY(), 0f); objectAnimator.setDuration(240); objectAnimator.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float currentValue = (Float) animation.getAnimatedValue(); float percent = currentValue * 1.0f / mContentViewTranslateY; mViewPager.setTranslationY(mViewPagerTranslateY * percent); } }); objectAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); isAnimating = false; } }); objectAnimator.start(); } /** * 收缩 */ public void shrink() { ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mContentView, "translationY", mContentView.getTranslationY(), -mContentViewTranslateY); objectAnimator.setDuration(240); objectAnimator.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float currentValue = (Float) animation.getAnimatedValue(); float percent = currentValue * 1.0f / mContentViewTranslateY; mViewPager.setTranslationY(mViewPagerTranslateY * percent); } }); objectAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); isAnimating = false; } }); objectAnimator.start(); } /** * ContentView是否滚动到顶部 */ private boolean isScrollTop() { if (mContentView instanceof RecyclerView) return ((RecyclerView) mContentView).computeVerticalScrollOffset() == 0; if (mContentView instanceof AbsListView) { boolean result = false; AbsListView listView = (AbsListView) mContentView; if (listView.getFirstVisiblePosition() == 0) { final View topChildView = listView.getChildAt(0); result = topChildView.getTop() == 0; } return result; } return mContentView.getScrollY() == 0; } }