package com.youplayer.player.frame;
import java.util.Stack;
import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.Scroller;
import com.youplayer.core.You_Core;
import com.youplayer.core.struct.You_core_push_or_pop_page_data_t;
import com.youplayer.player.YouPlayerAbsoluteLayout;
import com.youplayer.player.R;
import com.youplayer.util.LOG;
public class YouPlayerContainerView extends FrameLayout implements YouPlayerActionHandler {
private static final String TAG = "ContainerView";
public static final int HIDE_BOTH = 0;
public static final int HIDE_LEFT = 1;
public static final int HIDE_RIGHT = 2;
public static boolean canSlidingAround = false;
public int viewLevel = 0;
public YouPlayerViewControler currentViewControler;
public Stack<YouPlayerViewControler> stack = new Stack<YouPlayerViewControler>();
public int currentHideType = HIDE_BOTH;
private GestureDetector mGestureDetector;
private FlingGestureDetectorListener mGestureDetectorListener;
private GestureDetector mInterruptDetector;
private int criticalValues;
private boolean mIsTouched = false;
private int mAnimationDuration = 250;
private int mGalleryWidth = 0;
public int hideWidth;
private long mScrollTimestamp = 0;
private int mDetectScrollX = 50;
private int fling_width;
private YouPlayerAbsoluteLayout.LayoutParams layoutParams;
private boolean mIsDragging = false;
private float mCurrentOffset = 0.0f;
private boolean isIntercept;
private boolean isMoveable = false;
private OnHideListener hideListener;
private Scroller mScroller;
public static YouPlayerContainerView instance;
public YouPlayerContainerView(Context context) {
this(context, null);
}
public YouPlayerContainerView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public YouPlayerContainerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mGestureDetectorListener = new FlingGestureDetectorListener();
mGestureDetector = new GestureDetector(mGestureDetectorListener);
mInterruptDetector = new GestureDetector(new InterruptGestureDetectorListener());
fling_width = (int) getContext().getResources().getDimension(R.dimen.fling_width);
mScroller = new Scroller(context);
initHandler(context);
instance = this;
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
mGalleryWidth = right - left;
criticalValues = mGalleryWidth / 3;
hideWidth = mGalleryWidth * 5 / 6;
super.onLayout(changed, left, top, right, bottom);
}
private Handler mHandler;
private void initHandler(Context context) {
mHandler = new Handler(context.getMainLooper());
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean result;
if (!isIntercept && isMoveable) {
if(ev == null)
Log.v(TAG, " onInterceptTouchEvent ev == null ");
result = mInterruptDetector.onTouchEvent(ev);
} else {
result = super.onInterceptTouchEvent(ev);
}
return result;
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
boolean result = super.dispatchTouchEvent(ev);
if (ev.getAction() == MotionEvent.ACTION_UP) {
isIntercept = false;
}
return result;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// 视图层级为1时容器才能左右移动
if (viewLevel == 1) {
if(event == null)
Log.v(TAG, " onTouchEvent event == null ");
onContainerTouchEvent(event);
}
return true;
}
public boolean onContainerTouchEvent(MotionEvent event) {
boolean consumed = mGestureDetector.onTouchEvent(event);
if (event.getAction() == MotionEvent.ACTION_UP) {
if (mIsTouched || mIsDragging) {
mIsTouched = false;
mIsDragging = false;
if (currentHideType == HIDE_BOTH) {
if (layoutParams == null) {
layoutParams = (YouPlayerAbsoluteLayout.LayoutParams) getLayoutParams();
LOG.e(TAG, "onContainerTouchEvent", "layoutParams = " + layoutParams.toString());
}
int currX = layoutParams.x;
if (Math.abs(currX) < criticalValues) {
hide(HIDE_BOTH);
} else if (currX >= criticalValues) {
hide(HIDE_RIGHT);
} else if (currX <= -criticalValues) {
hide(HIDE_LEFT);
}
} else {
hide(HIDE_BOTH);
}
}
}
return consumed;
}
public YouPlayerViewControler getCurrentViewControler() {
return this.currentViewControler;
}
private void push( YouPlayerViewControler viewControler) {
LOG.v(TAG, "push()", "current hideType : " + currentHideType);
if (currentHideType != HIDE_BOTH) {
snake(viewControler);
} else {
if (viewLevel > 0) {
currentViewControler.onPause();
currentViewControler.onStop();
stack.add(currentViewControler);
getChildAt(getChildCount() - 1).setVisibility(View.GONE);
}
addView(viewControler.getView());
}
currentViewControler = viewControler;
viewLevel++;
LOG.i(TAG, "push()", "viewLevel = " + viewLevel);
}
private void pop() {
LOG.v(TAG, "pop()", "getChildCount = " + getChildCount());
currentViewControler.finish();
removeViewAt(getChildCount() - 1);
if (getChildCount() > 0) {
getChildAt(getChildCount() - 1).setVisibility(View.VISIBLE);
}
if (stack.size() > 0) {
currentViewControler = null;
currentViewControler = stack.pop();
currentViewControler.onResume();
LOG.v(TAG, "pop()","currentViewControler : " + currentViewControler.getClass());
}
viewLevel--;
LOG.i(TAG, "pop()", "viewLevel = " + viewLevel);
}
private void popAll() {
currentViewControler.finish();
removeAllViews();
if (stack.size() > 0) {
stack.clear();
LOG.v(TAG, "stack.clear()"," " );
}
viewLevel = 0;
LOG.i(TAG, "popAll()", "viewLevel = " + viewLevel);
}
private void snake(YouPlayerViewControler view) {
if (layoutParams == null) {
layoutParams = (YouPlayerAbsoluteLayout.LayoutParams) getLayoutParams();
LOG.e(TAG, "snake", "layoutParams = " + layoutParams.toString());
}
targetType = -1;
int delta = 0;
switch (currentHideType) {
case HIDE_RIGHT:
delta = layoutParams.x - mGalleryWidth;
break;
case HIDE_BOTH:
delta = layoutParams.x;
break;
case HIDE_LEFT:
delta = layoutParams.x + mGalleryWidth;
break;
default:
break;
}
addView(view.getView());
mScroller.startScroll(-layoutParams.x, 0, delta, 0, 300);
YouPlayerAppFrame.youExplorer.invalidate();
LOG.v(TAG, "snake()", "current hideType : " + currentHideType);
}
public void onComputeScroll() {
if (mScroller.computeScrollOffset()) {
layoutParams.x = -mScroller.getCurrX();
requestLayout();
YouPlayerAppFrame.youExplorer.postInvalidate();
if(mScroller.isFinished()) {
if(targetType == -1) {
targetType = HIDE_BOTH;
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mScroller.startScroll(-layoutParams.x, 0, layoutParams.x, 0, 300);
YouPlayerAppFrame.youExplorer.invalidate();
}
}, 150);
} else {
moveEnd();
}
}
}
super.computeScroll();
}
public void hide(int hideType) {
if (layoutParams == null) {
layoutParams = (YouPlayerAbsoluteLayout.LayoutParams) getLayoutParams();
}
LOG.v(TAG, "hide()", "hideType : " + hideType + " mIsTouched : "+ mIsTouched);
if (!(mIsTouched && mIsDragging)) {
moveStart(hideType);
int delta = 0;
switch (hideType) {
case HIDE_RIGHT:
delta = layoutParams.x - hideWidth;
break;
case HIDE_BOTH:
delta = layoutParams.x;
break;
case HIDE_LEFT:
delta = hideWidth + layoutParams.x;
break;
default:
break;
}
mScroller.startScroll(-layoutParams.x, 0, delta, 0, 300);
YouPlayerAppFrame.youExplorer.invalidate();
}
}
public void setInterceptTouchEvent(boolean isIntercept) {
LOG.v(TAG, "setInterceptTouchEvent()", " isIntercept : " + isIntercept);
this.isIntercept = isIntercept;
}
private void setMoveable(boolean isMoveable) {
this.isMoveable = isMoveable;
}
public void setOnHideListener(OnHideListener hideListener) {
this.hideListener = hideListener;
}
public interface OnHideListener {
void goHide(int hideType);
}
private class FlingGestureDetectorListener extends GestureDetector.SimpleOnGestureListener {
private float moveXPosition;
public void setDownEvent(float moveXPosition, float moveYPosition) {// 复原丢失的Down触摸消息
if (layoutParams == null) {
layoutParams = (YouPlayerAbsoluteLayout.LayoutParams) getLayoutParams();
}
this.moveXPosition = moveXPosition;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
// 左右滑动唤出菜单开关
if(canSlidingAround){
if (e2.getAction() == MotionEvent.ACTION_MOVE) {
if (layoutParams == null) {
layoutParams = (YouPlayerAbsoluteLayout.LayoutParams) getLayoutParams();
LOG.e(TAG, "onScroll()", "layoutParams = " + layoutParams.toString());
}
if (mIsDragging == false) {
mIsTouched = true;
mIsDragging = true;
mScrollTimestamp = System.currentTimeMillis();
mCurrentOffset = layoutParams.x;
}
float maxVelocity = mGalleryWidth
/ (mAnimationDuration / 1000.0f);
long timestampDelta = System.currentTimeMillis()
- mScrollTimestamp;
float maxScrollDelta = maxVelocity * (timestampDelta / 1000.0f);
float currentScrollDelta = e2.getRawX() - moveXPosition;
if (currentScrollDelta < maxScrollDelta * -1)
currentScrollDelta = maxScrollDelta * -1;
if (currentScrollDelta > maxScrollDelta)
currentScrollDelta = maxScrollDelta;
int scrollOffset = Math.round(mCurrentOffset
+ currentScrollDelta);
if (scrollOffset >= fling_width)
scrollOffset = fling_width;
if (scrollOffset <= fling_width * -1)
scrollOffset = fling_width * -1;
if (scrollOffset != 0) {
if ((layoutParams.x == 0)
|| ((scrollOffset * layoutParams.x) < 0)) {
if (scrollOffset < 0) {
hideListener.goHide(HIDE_LEFT);
moveStart(HIDE_LEFT);
} else if (scrollOffset > 0) {
hideListener.goHide(HIDE_RIGHT);
moveStart(HIDE_RIGHT);
}
}
}
if(Math.abs(layoutParams.x - scrollOffset) > 2) {
layoutParams.x = scrollOffset;
requestLayout();
}
}
LOG.v(TAG, "onScroll()", " onScroll End");
}
return false;
}
}
private class InterruptGestureDetectorListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onDown(MotionEvent e) {
mIsTouched = true;
if (currentHideType != HIDE_BOTH) {
mGestureDetectorListener.setDownEvent(e.getRawX(), e.getRawY());
return true;
}
return false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
if(e2 == null)
Log.v(TAG, "InterruptGestureDetectorListener onScroll e2 == null ");
if(e1 == null)
Log.v(TAG, "InterruptGestureDetectorListener onScroll e1 == null " + (e1 == null));
if (e2.getAction() == MotionEvent.ACTION_MOVE) {
float maxVelocity = mGalleryWidth
/ (mAnimationDuration / 1000.0f);
long timestampDelta = System.currentTimeMillis()
- mScrollTimestamp;
float maxScrollDelta = maxVelocity * (timestampDelta / 1000.0f);
float currentScrollDelta = e2.getRawX() - e1.getRawX();
float currentScrollYDelta = e2.getRawY() - e1.getRawY();
if (currentScrollDelta < maxScrollDelta * -1)
currentScrollDelta = maxScrollDelta * -1;
if (currentScrollDelta > maxScrollDelta)
currentScrollDelta = maxScrollDelta;
if (Math.abs(currentScrollDelta) > mDetectScrollX || Math.abs(currentScrollYDelta) > mDetectScrollX) {
isIntercept = true;
float dy = e2.getRawY() - e1.getRawY();
double tan = dy / currentScrollDelta;
if (tan > -0.58 && tan < 0.58) {
mGestureDetectorListener.setDownEvent(e2.getRawX(), e2.getRawY());
return true;
}
}
}
return false;
}
}
@Override
public boolean action_callback(int page_id, int page_action,
Object core_data, Object ui_data) {
boolean result = true;
switch (page_action) {
case You_Core.FN_PAGE_EVT_PUSH:
LOG.i(TAG, "handlerCallBack()", " pushPage " + page_id + " "+ core_data);
pushPage(core_data, ui_data);
return true;
// 删除视图
case You_Core.FN_PAGE_EVT_POP:
LOG.i(TAG, "handlerCallBack()", " popPage " + page_id + " "+ core_data);
popPage(core_data);
return true;
// 显示当前视图
case You_Core.FN_PAGE_EVT_REMAIN:
LOG.i(TAG, "handlerCallBack()", " remainPage " + page_id + " "+ core_data);
remainPage(page_id, core_data, ui_data);
return true;
case You_Core.FN_PAGE_EVT_POP_TO_PAGE:
LOG.i(TAG, "handlerCallBack()", " pop to page " + page_id + " "+ core_data);
popToPage(core_data);
return true;
default:
result = false;
break;
}
return result;
}
private void pushPage(Object core_data, Object ui_data) {
int page_type =((You_core_push_or_pop_page_data_t)core_data).page_type;
LOG.v(TAG, "pushPage()", " page_type : " + page_type + "");
push(YouPlayerViewControlerFactory.createViewByPageType(getContext().getApplicationContext(), page_type,core_data, ui_data));
setMoveable(true);
}
// popPage 与 show 存在异步执行的问题 固在pop时加同步关键字
private synchronized void popPage(Object core_data){
boolean isRoot = ((You_core_push_or_pop_page_data_t) core_data).isRoot;
if(isRoot){
popAll();
}else{
pop();
}
}
private synchronized void popToPage(Object core_data){
int page_type = ((You_core_push_or_pop_page_data_t) core_data).page_type;
removeViewAt(getChildCount()-1);
int size = stack.size();
for (int i = 0; i < size; i++) {
currentViewControler = null;
currentViewControler = stack.pop();
viewLevel--;
if(page_type == currentViewControler.getTag()){
getChildAt(getChildCount()-1).setVisibility(View.VISIBLE);
return;
}else{
removeViewAt(getChildCount()-1);
}
}
}
private void remainPage(int page_id, Object core_data, Object ui_data) {
hide(HIDE_BOTH);
}
private int targetType;
private void moveStart(int hideType) {
targetType = hideType;
currentViewControler.onPause();
}
private void moveEnd() {
switch (targetType) {
case HIDE_BOTH:
currentViewControler.onResume();
break;
case HIDE_RIGHT:
break;
case HIDE_LEFT:
break;
default:
break;
}
currentHideType = targetType;
}
}