package com.steven.babyiyo.component;
import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
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.steven.babyiyo.R;
/**
* ���������������
* @author sjy
* @param <T>
*/
public abstract class PullToZoomBase<T extends View> extends LinearLayout{
/**����ϵ��*/
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;
protected 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;
}
public T getPullRootView() {
return mRootView;
}
public View getZoomView() {
return mZoomView;
}
public View getHeaderView() {
return mHeaderView;
}
public boolean isPullToZoomEnabled() {
return isZoomEnabled;
}
public boolean isZooming() {
return isZooming;
}
public boolean isParallax() {
return isParallax;
}
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 (isReadyForPullDown()) {
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 && isReadyForPullDown()) {
mLastMotionY = y;
mLastMotionX = x;
mIsBeingDragged = true;
}
}
}
break;
}
case MotionEvent.ACTION_DOWN: {
if (isReadyForPullDown()) {
mLastMotionY = mInitialMotionY = event.getY();
mLastMotionX = mInitialMotionX = event.getX();
mIsBeingDragged = false;
}
break;
}
}
return mIsBeingDragged;
}
@Override
public boolean onTouchEvent(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 (isReadyForPullDown()) {
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();
}
onZoomRelease(mInitialMotionY, mLastMotionY);
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);
}
}
public abstract void handleStyledAttributes(TypedArray a);
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 isReadyForPullDown();
protected abstract boolean isReadyForPullUp();
/**
* �ͷ�����
* @param initMotionY ���ſ�ʼʱ��Yλ��
* @param lastMotionY �����ͷ�ʱ��Yλ��
*/
protected abstract void onZoomRelease(float initMotionY, float lastMotionY);
public interface OnPullZoomListener {
public void onPullZooming(int newScrollValue);
public void onPullZoomEnd();
public void onRefresh();
public void onLoad();
}
}