individual.leobert.calendar.CalendarLayout.java Source code

Java tutorial

Introduction

Here is the source code for individual.leobert.calendar.CalendarLayout.java

Source

/*
 * Copyright 2016,leobert,The Android Open Source Project
 *
 * 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 individual.leobert.calendar;

import android.content.Context;
import android.graphics.Rect;
import android.support.v4.view.VelocityTrackerCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ScrollerCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.animation.Interpolator;
import android.widget.AbsListView;
import android.widget.FrameLayout;
import android.widget.ListView;

public class CalendarLayout extends FrameLayout {

    private static final String TAG = "CalendarLayout";

    private View view1;
    private ViewGroup view2;
    private CalendarTopView mTopView;
    //
    public static final int TYPE_OPEN = 0;
    //?
    public static final int TYPE_FOLD = 1;
    public int type = TYPE_FOLD;

    //?
    private boolean isSilde = false;

    private int topHeigth;
    private int itemHeight;
    private int bottomViewTopHeight;
    private int maxDistance;

    private ScrollerCompat mScroller;
    private float mMaxVelocity;
    private float mMinVelocity;
    private int activitPotionerId;

    private static final Interpolator sInterpolator = new Interpolator() {
        @Override
        public float getInterpolation(float t) {
            t -= 1.0f;
            return t * t * t * t * t + 1.0f;
        }
    };

    public CalendarLayout(Context context) {
        super(context);
        init();
    }

    public CalendarLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        final CalendarTopView viewPager = (CalendarTopView) getChildAt(0);

        mTopView = viewPager;
        view1 = (View) viewPager;
        view2 = (ViewGroup) getChildAt(1);

        mTopView.setCalendarTopViewChangeListener(new CalendarTopViewChangeListener() {
            @Override
            public void onLayoutChange(CalendarTopView topView) {
                CalendarLayout.this.requestLayout();
            }
        });
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        itemHeight = mTopView.getItemHeight();
        topHeigth = view1.getMeasuredHeight();
        maxDistance = topHeigth - itemHeight;

        switch (type) {
        case TYPE_FOLD:
            bottomViewTopHeight = itemHeight;
            break;
        case TYPE_OPEN:
            bottomViewTopHeight = topHeigth;
            break;
        }
        view2.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(
                MeasureSpec.getSize(heightMeasureSpec) - mTopView.getItemHeight(), MeasureSpec.EXACTLY));
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        view2.offsetTopAndBottom(bottomViewTopHeight);
        int[] selectRct = getSelectRect();
        if (type == TYPE_FOLD) {
            view1.offsetTopAndBottom(-selectRct[1]);
        }
    }

    private void init() {

        final ViewConfiguration vc = ViewConfiguration.get(getContext());

        mMaxVelocity = vc.getScaledMaximumFlingVelocity();
        mMinVelocity = vc.getScaledMinimumFlingVelocity();
        mScroller = ScrollerCompat.create(getContext(), sInterpolator);
    }

    float oy, ox;
    boolean isClickBtottomView = false;

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        //        mViewDragHelper.shouldInterceptTouchEvent(ev);
        boolean isflag = false;

        //?
        switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            oy = ev.getY();
            ox = ev.getX();
            isClickBtottomView = isClickView(view2, ev);
            cancel();
            activitPotionerId = ev.getPointerId(0);

            int top = view2.getTop();

            if (top < topHeigth) {
                type = TYPE_FOLD;
            } else {
                type = TYPE_OPEN;
            }
            break;
        case MotionEvent.ACTION_MOVE:
            float y = ev.getY();
            float x = ev.getX();

            float xdiff = x - ox;
            float ydiff = y - oy;

            if (Math.abs(ydiff) > 5 && Math.abs(ydiff) > Math.abs(xdiff)) {
                isflag = true;

                if (isClickBtottomView) {
                    boolean isScroll = isScroll(view2);
                    if (ydiff > 0) {
                        //?
                        if (type == TYPE_OPEN) {
                            return super.onInterceptTouchEvent(ev);
                        } else {
                            if (isScroll) {
                                return super.onInterceptTouchEvent(ev);
                            }

                        }
                    } else {
                        //?
                        if (type == TYPE_FOLD) {
                            return super.onInterceptTouchEvent(ev);
                        } else {
                            if (isScroll) {
                                return super.onInterceptTouchEvent(ev);
                            }
                        }
                    }

                }
            }
            ox = x;
            oy = y;
            break;
        case MotionEvent.ACTION_UP:

            break;
        }
        return isSilde || isflag || super.onInterceptTouchEvent(ev);
    }

    private boolean isScroll(ViewGroup view2) {
        View fistChildView = view2.getChildAt(0);
        if (fistChildView == null) {
            return false;
        }

        if (view2 instanceof ListView) {
            AbsListView list = (AbsListView) view2;
            if (fistChildView.getTop() != 0) {
                return true;
            } else {
                if (list.getPositionForView(fistChildView) != 0) {
                    return true;
                }
            }
        }

        return false;
    }

    public boolean isClickView(View view, MotionEvent ev) {
        Rect rect = new Rect();
        view.getHitRect(rect);
        boolean isClick = rect.contains((int) ev.getX(), (int) ev.getY());
        Log.d(TAG, "isClickView() called with: isClick = [" + isClick + "]");
        return isClick;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        processTouchEvent(event);
        return true;
    }

    private VelocityTracker mVelocityTracker;

    public void processTouchEvent(MotionEvent event) {

        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }
        mVelocityTracker.addMovement(event);

        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            break;
        case MotionEvent.ACTION_MOVE:
            if (isSilde) {
                return;
            }
            float cy = event.getY();
            int dy = (int) (cy - oy);

            if (dy == 0) {
                return;
            }
            oy = cy;
            move(dy);

            break;
        case MotionEvent.ACTION_UP:

            if (isSilde) {
                cancel();
                return;
            }

            //
            final int pointerId = activitPotionerId;
            mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
            float crrentV = VelocityTrackerCompat.getYVelocity(mVelocityTracker, pointerId);

            if (Math.abs(crrentV) > 2000) {
                if (crrentV > 0) {
                    open();
                } else {
                    flod();
                }
                cancel();
                return;
            }

            int top = view2.getTop() - topHeigth;
            int maxd = maxDistance;

            if (Math.abs(top) < maxd / 2) {
                open();
            } else {
                flod();
            }
            cancel();

            break;
        case MotionEvent.ACTION_CANCEL:
            cancel();
            break;
        }
    }

    public void open() {
        startScroll(view2.getTop(), topHeigth);
    }

    public void flod() {
        startScroll(view2.getTop(), topHeigth - maxDistance);
    }

    private int[] getSelectRect() {
        return mTopView.getCurrentSelectPosition();
    }

    private void move(int dy) {

        int[] selectRect = getSelectRect();
        int itemHeight = mTopView.getItemHeight();

        int dy1 = getAreaValue(view1.getTop(), dy, -selectRect[1], 0);
        int dy2 = getAreaValue(view2.getTop() - topHeigth, dy, -(topHeigth - itemHeight), 0);

        if (dy1 != 0) {
            ViewCompat.offsetTopAndBottom(view1, dy1);
        }

        if (dy2 != 0) {
            ViewCompat.offsetTopAndBottom(view2, dy2);
        }

    }

    private int getAreaValue(int top, int dy, int minValue, int maxValue) {

        if (top + dy < minValue) {
            return minValue - top;
        }

        if (top + dy > maxValue) {
            return maxValue - top;
        }
        return dy;
    }

    private void startScroll(int startY, int endY) {

        float distance = endY - startY;
        float t = distance / maxDistance * 600;

        mScroller.startScroll(0, 0, 0, endY - startY, (int) Math.abs(t));
        postInvalidate();
    }

    int oldY = 0;

    @Override
    public void computeScroll() {
        super.computeScroll();

        bottomViewTopHeight = view2.getTop();
        if (mScroller.computeScrollOffset()) {
            isSilde = true;
            int cy = mScroller.getCurrY();
            int dy = cy - oldY;
            move(dy);
            oldY = cy;
            postInvalidate();
        } else {
            oldY = 0;
            isSilde = false;
        }
    }

    public void cancel() {
        if (mVelocityTracker != null) {
            mVelocityTracker.recycle();
            mVelocityTracker = null;
        }
    }

}