package com.todayinfo.ui.component.pulltozoomview; import android.app.Activity; import android.content.Context; import android.content.res.TypedArray; import android.support.annotation.NonNull; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.widget.LinearLayout; import com.jinghua.todayinformation.R; /** * Author: ZhuWenWu Version V1.0 Date: 2014/11/7 14:18. Description: * Modification History: Date Author Version Description * ------------------------ * ----------------------------------------------------------- 2014/11/7 * ZhuWenWu 1.0 1.0 Why & What is modified: */ public abstract class PullToZoomBase<T extends View> extends LinearLayout implements IPullToZoom<T> { private static final float FRICTION = 2.0f; protected T mRootView; protected View mHeaderView;// 头部View protected View mZoomView;// 缩放拉伸View protected int mScreenHeight; protected int mScreenWidth; private boolean isZoomEnabled = true; private boolean isParallax = true; private boolean isZooming = false; private boolean isHideHeader = false; private int mTouchSlop; private boolean mIsBeingDragged = false; private float mLastMotionY; private float mLastMotionX; private float mInitialMotionY; private float mInitialMotionX; private OnPullZoomListener onPullZoomListener; public PullToZoomBase(Context context) { this(context, null); } public PullToZoomBase(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs); } private void init(Context context, AttributeSet attrs) { setGravity(Gravity.CENTER); ViewConfiguration config = ViewConfiguration.get(context); mTouchSlop = config.getScaledTouchSlop(); DisplayMetrics localDisplayMetrics = new DisplayMetrics(); ((Activity) getContext()).getWindowManager().getDefaultDisplay() .getMetrics(localDisplayMetrics); mScreenHeight = localDisplayMetrics.heightPixels; mScreenWidth = localDisplayMetrics.widthPixels; // Refreshable View // By passing the attrs, we can add ListView/GridView params via XML mRootView = createRootView(context, attrs); if (attrs != null) { LayoutInflater mLayoutInflater = LayoutInflater.from(getContext()); // 初始化状态View TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.PullToZoomView); int zoomViewResId = a.getResourceId( R.styleable.PullToZoomView_zoomView, 0); if (zoomViewResId > 0) { mZoomView = mLayoutInflater.inflate(zoomViewResId, null, false); } int headerViewResId = a.getResourceId( R.styleable.PullToZoomView_headerView, 0); if (headerViewResId > 0) { mHeaderView = mLayoutInflater.inflate(headerViewResId, null, false); } isParallax = a.getBoolean( R.styleable.PullToZoomView_isHeaderParallax, true); // Let the derivative classes have a go at handling attributes, then // recycle them... handleStyledAttributes(a); a.recycle(); } addView(mRootView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); } public void setOnPullZoomListener(OnPullZoomListener onPullZoomListener) { this.onPullZoomListener = onPullZoomListener; } @Override public T getPullRootView() { return mRootView; } @Override public View getZoomView() { return mZoomView; } @Override public View getHeaderView() { return mHeaderView; } @Override public boolean isPullToZoomEnabled() { return isZoomEnabled; } @Override public boolean isZooming() { return isZooming; } @Override public boolean isParallax() { return isParallax; } @Override public boolean isHideHeader() { return isHideHeader; } public void setZoomEnabled(boolean isZoomEnabled) { this.isZoomEnabled = isZoomEnabled; } public void setParallax(boolean isParallax) { this.isParallax = isParallax; } public void setHideHeader(boolean isHideHeader) {// header显示才能Zoom this.isHideHeader = isHideHeader; } @Override public boolean onInterceptTouchEvent(MotionEvent event) { if (!isPullToZoomEnabled() || isHideHeader()) { return false; } final int action = event.getAction(); if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { mIsBeingDragged = false; return false; } if (action != MotionEvent.ACTION_DOWN && mIsBeingDragged) { return true; } switch (action) { case MotionEvent.ACTION_MOVE: { if (isReadyForPullStart()) { final float y = event.getY(), x = event.getX(); final float diff, oppositeDiff, absDiff; // We need to use the correct values, based on scroll // direction diff = y - mLastMotionY; oppositeDiff = x - mLastMotionX; absDiff = Math.abs(diff); if (absDiff > mTouchSlop && absDiff > Math.abs(oppositeDiff)) { if (diff >= 1f && isReadyForPullStart()) { mLastMotionY = y; mLastMotionX = x; mIsBeingDragged = true; } } } break; } case MotionEvent.ACTION_DOWN: { if (isReadyForPullStart()) { mLastMotionY = mInitialMotionY = event.getY(); mLastMotionX = mInitialMotionX = event.getX(); mIsBeingDragged = false; } break; } } return mIsBeingDragged; } @Override public boolean onTouchEvent(@NonNull MotionEvent event) { if (!isPullToZoomEnabled() || isHideHeader()) { return false; } if (event.getAction() == MotionEvent.ACTION_DOWN && event.getEdgeFlags() != 0) { return false; } switch (event.getAction()) { case MotionEvent.ACTION_MOVE: { if (mIsBeingDragged) { mLastMotionY = event.getY(); mLastMotionX = event.getX(); pullEvent(); isZooming = true; return true; } break; } case MotionEvent.ACTION_DOWN: { if (isReadyForPullStart()) { mLastMotionY = mInitialMotionY = event.getY(); mLastMotionX = mInitialMotionX = event.getX(); return true; } break; } case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: { if (mIsBeingDragged) { mIsBeingDragged = false; // If we're already refreshing, just scroll back to the top if (isZooming()) { smoothScrollToTop(); if (onPullZoomListener != null) { onPullZoomListener.onPullZoomEnd(); } isZooming = false; return true; } return true; } break; } } return false; } private void pullEvent() { final int newScrollValue; final float initialMotionValue, lastMotionValue; initialMotionValue = mInitialMotionY; lastMotionValue = mLastMotionY; newScrollValue = Math.round(Math.min(initialMotionValue - lastMotionValue, 0) / FRICTION); pullHeaderToZoom(newScrollValue); if (onPullZoomListener != null) { onPullZoomListener.onPullZooming(newScrollValue); } } protected abstract void pullHeaderToZoom(int newScrollValue); public abstract void setHeaderView(View headerView); public abstract void setZoomView(View zoomView); protected abstract T createRootView(Context context, AttributeSet attrs); protected abstract void smoothScrollToTop(); protected abstract boolean isReadyForPullStart(); public interface OnPullZoomListener { public void onPullZooming(int newScrollValue); public void onPullZoomEnd(); } }