package com.fsck.splitview; import com.actionbarsherlock.R; import android.content.Context; import android.content.res.TypedArray; import android.os.SystemClock; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.View.OnTouchListener; import android.widget.LinearLayout; // TODO: Auto-generated Javadoc /** * The Class SplitView. */ public class SplitView extends LinearLayout implements OnTouchListener { /** The m handle id. */ private int mHandleId; /** The m handle. */ private View mHandle; /** The m primary content id. */ private int mPrimaryContentId; /** The m primary content. */ private View mPrimaryContent; /** The m secondary content id. */ private int mSecondaryContentId; /** The m secondary content. */ private View mSecondaryContent; /** The m last primary content size. */ private int mLastPrimaryContentSize; /** The m dragging. */ @SuppressWarnings("unused") private boolean mDragging; /** The m dragging started. */ private long mDraggingStarted; /** The m drag start x. */ private float mDragStartX; /** The m drag start y. */ private float mDragStartY; /** The m pointer offset. */ private float mPointerOffset; /** The Constant MAXIMIZED_VIEW_TOLERANCE_DIP. */ final static private int MAXIMIZED_VIEW_TOLERANCE_DIP = 30; /** The Constant TAP_DRIFT_TOLERANCE. */ final static private int TAP_DRIFT_TOLERANCE = 3; /** The Constant SINGLE_TAP_MAX_TIME. */ final static private int SINGLE_TAP_MAX_TIME = 175; /** * Instantiates a new split view. * * @param context the context * @param attrs the attrs */ public SplitView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray viewAttrs = context.obtainStyledAttributes(attrs, R.styleable.SplitView); RuntimeException e = null; mHandleId = viewAttrs.getResourceId(R.styleable.SplitView_handle, 0); if (mHandleId == 0) { e = new IllegalArgumentException(viewAttrs.getPositionDescription() + ": The required attribute handle must refer to a valid child view."); } mPrimaryContentId = viewAttrs.getResourceId(R.styleable.SplitView_primaryContent, 0); if (mPrimaryContentId == 0) { e = new IllegalArgumentException(viewAttrs.getPositionDescription() + ": The required attribute primaryContent must refer to a valid child view."); } mSecondaryContentId = viewAttrs.getResourceId(R.styleable.SplitView_secondaryContent, 0); if (mSecondaryContentId == 0) { e = new IllegalArgumentException(viewAttrs.getPositionDescription() + ": The required attribute secondaryContent must refer to a valid child view."); } viewAttrs.recycle(); if (e != null) { throw e; } } /** * On finish inflate. */ @Override public void onFinishInflate() { super.onFinishInflate(); mHandle = findViewById(mHandleId); if (mHandle == null) { String name = getResources().getResourceEntryName(mHandleId); throw new RuntimeException("Your Panel must have a child View whose id attribute is 'R.id." + name + "'"); } mPrimaryContent = findViewById(mPrimaryContentId); if (mPrimaryContent == null) { String name = getResources().getResourceEntryName(mPrimaryContentId); throw new RuntimeException("Your Panel must have a child View whose id attribute is 'R.id." + name + "'"); } mLastPrimaryContentSize = getPrimaryContentSize(); mSecondaryContent = findViewById(mSecondaryContentId); if (mSecondaryContent == null) { String name = getResources().getResourceEntryName(mSecondaryContentId); throw new RuntimeException("Your Panel must have a child View whose id attribute is 'R.id." + name + "'"); } mHandle.setOnTouchListener(this); } /** * On touch. * * @param view the view * @param me the me * @return true, if successful */ @SuppressWarnings("unused") @Override public boolean onTouch(View view, MotionEvent me) { ViewGroup.LayoutParams thisParams = getLayoutParams(); // Only capture drag events if we start if (view != mHandle) { return false; } //Log.v("foo", "at "+SystemClock.elapsedRealtime()+" got touch event " + me); if (me.getAction() == MotionEvent.ACTION_DOWN) { mDragging = true; mDraggingStarted = SystemClock.elapsedRealtime(); mDragStartX = me.getX(); mDragStartY = me.getY(); if (getOrientation() == VERTICAL) { mPointerOffset = me.getRawY() - mPrimaryContent.getMeasuredHeight(); } else { mPointerOffset = me.getRawX() - mPrimaryContent.getMeasuredWidth(); } return true; } else if (me.getAction() == MotionEvent.ACTION_UP) { mDragging = false; if ( mDragStartX <(me.getX()+TAP_DRIFT_TOLERANCE) && mDragStartX > (me.getX() -TAP_DRIFT_TOLERANCE) && mDragStartY < (me.getY() + TAP_DRIFT_TOLERANCE) && mDragStartY > (me.getY() - TAP_DRIFT_TOLERANCE) && ((SystemClock.elapsedRealtime() - mDraggingStarted) < SINGLE_TAP_MAX_TIME)) { if (isPrimaryContentMaximized() || isSecondaryContentMaximized()) { setPrimaryContentSize(mLastPrimaryContentSize); } else { maximizeSecondaryContent(); } } return true; } else if (me.getAction() == MotionEvent.ACTION_MOVE) { if (getOrientation() == VERTICAL) { setPrimaryContentHeight( (int)(me.getRawY() - mPointerOffset)); } else { setPrimaryContentWidth( (int)(me.getRawX() - mPointerOffset)); } } return true; } /** * Gets the handle. * * @return the handle */ public View getHandle() { return mHandle; } /** * Gets the primary content size. * * @return the primary content size */ public int getPrimaryContentSize() { if (getOrientation() == VERTICAL) { return mPrimaryContent.getMeasuredHeight(); } else { return mPrimaryContent.getMeasuredWidth(); } } /** * Sets the primary content size. * * @param newSize the new size * @return true, if successful */ public boolean setPrimaryContentSize(int newSize) { if (getOrientation() == VERTICAL) { return setPrimaryContentHeight(newSize); } else { return setPrimaryContentWidth(newSize); } } /** * Sets the primary content height. * * @param newHeight the new height * @return true, if successful */ private boolean setPrimaryContentHeight(int newHeight) { ViewGroup.LayoutParams params = mPrimaryContent.getLayoutParams(); if (mSecondaryContent.getMeasuredHeight() < 1 && newHeight > params.height) { return false; } if (newHeight >= 0) { params.height = newHeight; } unMinimizeSecondaryContent(); mPrimaryContent.setLayoutParams(params); return true; } /** * Sets the primary content width. * * @param newWidth the new width * @return true, if successful */ private boolean setPrimaryContentWidth(int newWidth) { ViewGroup.LayoutParams params = mPrimaryContent.getLayoutParams(); if (mSecondaryContent.getMeasuredWidth() < 1 && newWidth > params.width) { return false; } if (newWidth >= 0) { params.width = newWidth; } unMinimizeSecondaryContent(); mPrimaryContent.setLayoutParams(params); return true; } /** * Checks if is primary content maximized. * * @return true, if is primary content maximized */ public boolean isPrimaryContentMaximized() { if ( (getOrientation() == VERTICAL && (mSecondaryContent.getMeasuredHeight() < MAXIMIZED_VIEW_TOLERANCE_DIP) ) || (getOrientation() == HORIZONTAL && (mSecondaryContent.getMeasuredWidth() < MAXIMIZED_VIEW_TOLERANCE_DIP) )) { return true; } else { return false; } } /** * Checks if is secondary content maximized. * * @return true, if is secondary content maximized */ public boolean isSecondaryContentMaximized() { if ( (getOrientation() == VERTICAL && (mPrimaryContent.getMeasuredHeight() < MAXIMIZED_VIEW_TOLERANCE_DIP) ) || (getOrientation() == HORIZONTAL && (mPrimaryContent.getMeasuredWidth() < MAXIMIZED_VIEW_TOLERANCE_DIP) )) { return true; } else { return false; } } /** * Maximize primary content. */ public void maximizePrimaryContent() { maximizeContentPane(mPrimaryContent, mSecondaryContent); } /** * Maximize secondary content. */ public void maximizeSecondaryContent() { maximizeContentPane(mSecondaryContent, mPrimaryContent); } /** * Maximize content pane. * * @param toMaximize the to maximize * @param toUnMaximize the to un maximize */ @SuppressWarnings({ "deprecation" }) private void maximizeContentPane(View toMaximize, View toUnMaximize) { mLastPrimaryContentSize = getPrimaryContentSize(); ViewGroup.LayoutParams params = toUnMaximize.getLayoutParams(); ViewGroup.LayoutParams secondaryParams = toMaximize.getLayoutParams(); if (getOrientation() == VERTICAL) { params.height = 1; secondaryParams.height = LayoutParams.FILL_PARENT; //getLayoutParams().height - mHandle.getLayoutParams().height; } else { params.width = 1; secondaryParams.width = LayoutParams.FILL_PARENT; //getLayoutParams().width - mHandle.getLayoutParams().width; } toUnMaximize.setLayoutParams(params); toMaximize.setLayoutParams(secondaryParams); } /** * Un minimize secondary content. */ @SuppressWarnings("deprecation") private void unMinimizeSecondaryContent() { ViewGroup.LayoutParams secondaryParams = mSecondaryContent.getLayoutParams(); if (getOrientation() == VERTICAL) { secondaryParams.height = LayoutParams.FILL_PARENT; } else { secondaryParams.width = LayoutParams.FILL_PARENT; } mSecondaryContent.setLayoutParams(secondaryParams); } };