Commit 624a5a2d authored by Jean-Baptiste Kempf's avatar Jean-Baptiste Kempf
Browse files

Update SlidingMenu

parent 7fa279cd
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>
......@@ -5,8 +5,8 @@
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="4"
android:targetSdkVersion="14" />
android:minSdkVersion="5"
android:targetSdkVersion="16" />
<application>
<uses-library android:name="com.google.android.maps" />
......
......@@ -28,6 +28,15 @@
-->
<property file="ant.properties" />
<!-- if sdk.dir was not set from one of the property file, then
get it from the ANDROID_HOME env var.
This must be done before we load project.properties since
the proguard config can use sdk.dir -->
<property environment="env" />
<condition property="sdk.dir" value="${env.ANDROID_HOME}">
<isset property="env.ANDROID_HOME" />
</condition>
<!-- The project.properties file is created and updated by the 'android'
tool, as well as ADT.
......@@ -39,17 +48,9 @@
application and should be checked into Version Control Systems. -->
<loadproperties srcFile="project.properties" />
<property environment="env" />
<condition property="sdk.dir" value="${env.ANDROID_SDK}" >
<and>
<not><isset property="${env.ANDROID_SDK}"/></not>
<not><isset property="sdk.dir"/></not>
</and>
</condition>
<!-- quick check on sdk.dir -->
<fail
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var"
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
unless="sdk.dir"
/>
......
......@@ -9,4 +9,4 @@
android.library=true
# Project target.
target=android-14
target=android-15
......@@ -3,7 +3,8 @@
android:shape="rectangle" >
<gradient
android:endColor="#FF000000"
android:endColor="#99000000"
android:centerColor="#33000000"
android:startColor="#00000000" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:top="35dp">
<shape android:shape="rectangle" >
<solid android:color="@color/holo_blue_bright" />
<size android:height="@dimen/menu_header_line" />
</shape>
</item>
</layer-list>
\ No newline at end of file
......@@ -20,6 +20,7 @@
<attr name="viewAbove" format="reference" />
<attr name="viewBehind" format="reference" />
<attr name="behindOffset" format="dimension" />
<attr name="behindWidth" format="dimension" />
<attr name="behindScrollScale" format="float" />
<attr name="aboveTouchMode">
<enum name="margin" value="0" />
......@@ -33,6 +34,8 @@
<attr name="shadowWidth" format="dimension" />
<attr name="behindFadeEnabled" format="boolean" />
<attr name="behindFadeDegree" format="float" />
<attr name="selectorEnabled" format="boolean" />
<attr name="selectorDrawable" format="reference" />
</declare-styleable>
</resources>
\ No newline at end of file
package com.slidingmenu.lib;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Transformation;
import com.slidingmenu.lib.SlidingMenu.CanvasTransformer;
public class CustomViewBehind extends CustomViewAbove {
private static final String TAG = "CustomViewBehind";
private CustomViewAbove mViewAbove;
private CanvasTransformer mTransformer;
private boolean mChildrenEnabled;
public CustomViewBehind(Context context) {
......@@ -19,6 +27,21 @@ public class CustomViewBehind extends CustomViewAbove {
super(context, attrs, false);
}
public void setCustomViewAbove(CustomViewAbove customViewAbove) {
mViewAbove = customViewAbove;
mViewAbove.setTouchModeBehind(mTouchMode);
}
public void setTouchMode(int i) {
mTouchMode = i;
if (mViewAbove != null)
mViewAbove.setTouchModeBehind(i);
}
public void setCanvasTransformer(CanvasTransformer t) {
mTransformer = t;
}
public int getChildLeft(int i) {
return 0;
}
......@@ -47,19 +70,37 @@ public class CustomViewBehind extends CustomViewAbove {
public void setContent(View v) {
super.setMenu(v);
}
public void setChildrenEnabled(boolean enabled) {
mChildrenEnabled = enabled;
}
@Override
public void scrollTo(int x, int y) {
super.scrollTo(x, y);
if (mTransformer != null)
invalidate();
}
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
return !mChildrenEnabled;
}
@Override
public boolean onTouchEvent(MotionEvent e) {
return false;
}
@Override
protected void dispatchDraw(Canvas canvas) {
if (mTransformer != null) {
canvas.save();
mTransformer.transformCanvas(canvas, mViewAbove.getPercentOpen());
super.dispatchDraw(canvas);
canvas.restore();
} else
super.dispatchDraw(canvas);
}
}
package com.slidingmenu.lib;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import java.lang.reflect.Method;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.os.Build;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.v4.os.ParcelableCompat;
import android.support.v4.os.ParcelableCompatCreatorCallbacks;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.RelativeLayout;
......@@ -26,18 +32,59 @@ public class SlidingMenu extends RelativeLayout {
private CustomViewAbove mViewAbove;
private CustomViewBehind mViewBehind;
private OnOpenListener mOpenListener;
private OnCloseListener mCloseListener;
private boolean mSlidingEnabled;
public static void attachSlidingMenu(Activity activity, SlidingMenu sm, boolean slidingTitle) {
if (sm.getParent() != null)
throw new IllegalStateException("SlidingMenu cannot be attached to another view when" +
" calling the static method attachSlidingMenu");
if (slidingTitle) {
// get the window background
TypedArray a = activity.getTheme().obtainStyledAttributes(new int[] {android.R.attr.windowBackground});
int background = a.getResourceId(0, 0);
// move everything into the SlidingMenu
ViewGroup decor = (ViewGroup) activity.getWindow().getDecorView();
ViewGroup decorChild = (ViewGroup) decor.getChildAt(0);
decor.removeAllViews();
// save ActionBar themes that have transparent assets
decorChild.setBackgroundResource(background);
sm.setContent(decorChild);
decor.addView(sm);
} else {
// take the above view out of
ViewGroup content = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT);
View above = content.getChildAt(0);
content.removeAllViews();
sm.setContent(above);
content.addView(sm, LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
}
}
public interface OnOpenListener {
public void onOpen();
}
public interface OnOpenedListener {
public void onOpened();
}
public interface OnCloseListener {
public void onClose();
}
public interface OnClosedListener {
public void onClosed();
}
public interface CanvasTransformer {
public void transformCanvas(Canvas canvas, float percentOpen);
}
public SlidingMenu(Context context) {
this(context, null);
}
......@@ -56,40 +103,49 @@ public class SlidingMenu extends RelativeLayout {
mViewAbove = new CustomViewAbove(context);
addView(mViewAbove, aboveParams);
// register the CustomViewBehind2 with the CustomViewAbove
mViewAbove.setCustomViewBehind2(mViewBehind);
mViewAbove.setCustomViewBehind(mViewBehind);
mViewBehind.setCustomViewAbove(mViewAbove);
mViewAbove.setOnPageChangeListener(new OnPageChangeListener() {
public static final int POSITION_OPEN = 0;
public static final int POSITION_CLOSE = 1;
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) { }
public void onPageScrollStateChanged(int state) { }
public void onPageSelected(int position) {
if (position == 0 && mOpenListener != null) {
if (position == POSITION_OPEN && mOpenListener != null) {
mOpenListener.onOpen();
} else if (position == 1 && mCloseListener != null) {
} else if (position == POSITION_CLOSE && mCloseListener != null) {
mCloseListener.onClose();
}
}
}
});
// now style everything!
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SlidingMenu);
// set the above and behind views if defined in xml
int viewAbove = ta.getResourceId(R.styleable.SlidingMenu_viewAbove, -1);
if (viewAbove != -1) {
View v = LayoutInflater.from(context).inflate(viewAbove, null);
setViewAbove(v);
}
if (viewAbove != -1)
setContent(viewAbove);
int viewBehind = ta.getResourceId(R.styleable.SlidingMenu_viewBehind, -1);
if (viewBehind != -1) {
View v = LayoutInflater.from(context).inflate(viewBehind, null);
setViewBehind(v);
}
if (viewBehind != -1)
setMenu(viewBehind);
int touchModeAbove = ta.getInt(R.styleable.SlidingMenu_aboveTouchMode, TOUCHMODE_MARGIN);
setTouchModeAbove(touchModeAbove);
int touchModeBehind = ta.getInt(R.styleable.SlidingMenu_behindTouchMode, TOUCHMODE_MARGIN);
setTouchModeBehind(touchModeBehind);
int offsetBehind = (int) ta.getDimension(R.styleable.SlidingMenu_behindOffset, 0);
setBehindOffset(offsetBehind);
float scrollOffsetBehind = ta.getFloat(R.styleable.SlidingMenu_behindScrollScale, 0.25f);
int offsetBehind = (int) ta.getDimension(R.styleable.SlidingMenu_behindOffset, -1);
int widthBehind = (int) ta.getDimension(R.styleable.SlidingMenu_behindWidth, -1);
if (offsetBehind != -1 && widthBehind != -1)
throw new IllegalStateException("Cannot set both behindOffset and behindWidth for a SlidingMenu");
else if (offsetBehind != -1)
setBehindOffset(offsetBehind);
else if (widthBehind != -1)
setBehindWidth(widthBehind);
else
setBehindOffset(0);
float scrollOffsetBehind = ta.getFloat(R.styleable.SlidingMenu_behindScrollScale, 0.33f);
setBehindScrollScale(scrollOffsetBehind);
int shadowRes = ta.getResourceId(R.styleable.SlidingMenu_shadowDrawable, -1);
if (shadowRes != -1) {
......@@ -99,30 +155,32 @@ public class SlidingMenu extends RelativeLayout {
setShadowWidth(shadowWidth);
boolean fadeEnabled = ta.getBoolean(R.styleable.SlidingMenu_behindFadeEnabled, true);
setFadeEnabled(fadeEnabled);
float fadeDeg = ta.getFloat(R.styleable.SlidingMenu_behindFadeDegree, 0.5f);
float fadeDeg = ta.getFloat(R.styleable.SlidingMenu_behindFadeDegree, 0.66f);
setFadeDegree(fadeDeg);
// showAbove();
boolean selectorEnabled = ta.getBoolean(R.styleable.SlidingMenu_selectorEnabled, false);
setSelectorEnabled(selectorEnabled);
int selectorRes = ta.getResourceId(R.styleable.SlidingMenu_selectorDrawable, -1);
if (selectorRes != -1)
setSelectorDrawable(selectorRes);
}
public void setViewAbove(int res) {
setViewAbove(LayoutInflater.from(getContext()).inflate(res, null));
public void setContent(int res) {
setContent(LayoutInflater.from(getContext()).inflate(res, null));
}
public void setViewAbove(View v) {
public void setContent(View v) {
mViewAbove.setContent(v);
mViewAbove.invalidate();
mViewAbove.dataSetChanged();
showAbove();
}
public void setViewBehind(int res) {
setViewBehind(LayoutInflater.from(getContext()).inflate(res, null));
public void setMenu(int res) {
setMenu(LayoutInflater.from(getContext()).inflate(res, null));
}
public void setViewBehind(View v) {
mViewBehind.setContent(v);
public void setMenu(View v) {
mViewBehind.setMenu(v);
mViewBehind.invalidate();
mViewBehind.dataSetChanged();
}
public void setSlidingEnabled(boolean b) {
......@@ -141,13 +199,13 @@ public class SlidingMenu extends RelativeLayout {
public void setStatic(boolean b) {
if (b) {
setSlidingEnabled(false);
mViewAbove.setCustomViewBehind2(null);
mViewAbove.setCustomViewBehind(null);
mViewAbove.setCurrentItem(1);
mViewBehind.setCurrentItem(0);
} else {
mViewAbove.setCurrentItem(1);
mViewBehind.setCurrentItem(1);
mViewAbove.setCustomViewBehind2(mViewBehind);
mViewAbove.setCustomViewBehind(mViewBehind);
setSlidingEnabled(true);
}
}
......@@ -194,6 +252,24 @@ public class SlidingMenu extends RelativeLayout {
params.setMargins(left, top, i, bottom);
}
@SuppressWarnings("deprecation")
public void setBehindWidth(int i) {
int width;
Display display = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay();
try {
Class<?> cls = Display.class;
Class<?>[] parameterTypes = {Point.class};
Point parameter = new Point();
Method method = cls.getMethod("getSize", parameterTypes);
method.invoke(display, parameter);
width = parameter.x;
} catch (Exception e) {
width = display.getWidth();
}
setBehindOffset(width-i);
}
/**
*
* @param res The dimension resource to be set as the behind offset
......@@ -220,8 +296,12 @@ public class SlidingMenu extends RelativeLayout {
mViewAbove.setScrollScale(f);
}
public void setBehindCanvasTransformer(CanvasTransformer t) {
mViewBehind.setCanvasTransformer(t);
}
public int getTouchModeAbove() {
return mViewAbove.getTouchModeAbove();
return mViewAbove.getTouchMode();
}
public void setTouchModeAbove(int i) {
......@@ -229,11 +309,11 @@ public class SlidingMenu extends RelativeLayout {
throw new IllegalStateException("TouchMode must be set to either" +
"TOUCHMODE_FULLSCREEN or TOUCHMODE_MARGIN.");
}
mViewAbove.setTouchModeAbove(i);
mViewAbove.setTouchMode(i);
}
public int getTouchModeBehind() {
return mViewAbove.getTouchModeBehind();
return mViewBehind.getTouchMode();
}
public void setTouchModeBehind(int i) {
......@@ -241,7 +321,7 @@ public class SlidingMenu extends RelativeLayout {
throw new IllegalStateException("TouchMode must be set to either" +
"TOUCHMODE_FULLSCREEN or TOUCHMODE_MARGIN.");
}
mViewAbove.setTouchModeBehind(i);
mViewBehind.setTouchMode(i);
}
public void setShadowDrawable(int resId) {
......@@ -264,15 +344,41 @@ public class SlidingMenu extends RelativeLayout {
mViewAbove.setBehindFadeDegree(f);
}
public void setSelectorEnabled(boolean b) {
mViewAbove.setSelectorEnabled(true);
}
public void setSelectedView(View v) {
mViewAbove.setSelectedView(v);
}
public void setSelectorDrawable(int res) {
mViewAbove.setSelectorDrawable(BitmapFactory.decodeResource(getResources(), res));
}
public void setSelectorDrawable(Bitmap b) {
mViewAbove.setSelectorDrawable(b);
}
public void setOnOpenListener(OnOpenListener listener) {
mViewAbove.setOnOpenListener(listener);
mOpenListener = listener;
}
public void setOnCloseListener(OnCloseListener listener) {
mViewAbove.setOnCloseListener(listener);
mCloseListener = listener;
}
public static class SavedState extends BaseSavedState {
public void setOnOpenedListener(OnOpenedListener listener) {
mViewAbove.setOnOpenedListener(listener);
}
public void setOnClosedListener(OnClosedListener listener) {
mViewAbove.setOnClosedListener(listener);
}
private static class SavedState extends BaseSavedState {
boolean mBehindShowing;
public SavedState(Parcelable superState) {
......@@ -304,16 +410,16 @@ public class SlidingMenu extends RelativeLayout {
}
}
public Parcelable onSaveInstanceState() {
@Override
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.mBehindShowing = isBehindShowing();
return ss;
}
public void onRestoreInstanceState(Parcelable state) {
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (!(state instanceof SavedState)) {
super.onRestoreInstanceState(state);
return;
......@@ -329,73 +435,16 @@ public class SlidingMenu extends RelativeLayout {
}
}
private static final int LOW_DPI_STATUS_BAR_HEIGHT = 19;
private static final int MEDIUM_DPI_STATUS_BAR_HEIGHT = 25;
private static final int HIGH_DPI_STATUS_BAR_HEIGHT = 38;
private static final int XHIGH_DPI_STATUS_BAR_HEIGHT = 50;
@Override
protected boolean fitSystemWindows(Rect insets) {
/**
* Find the height of the current system status bar.
* If this cannot be determined rely on a default.
*/
private static final int mHeightId = Resources.getSystem()
.getIdentifier("status_bar_height", "dimen", "android");
private static final int mBarHeight;
// Try to retrieve the system's status bar height
// by querying the system's resources.
static {
int mHeight = -1;
if (mHeightId != 0) {
try {
mHeight = Resources.getSystem().getDimensionPixelSize(mHeightId);
} catch(Resources.NotFoundException e) { }
}
mBarHeight = mHeight;
};
int leftPadding = getPaddingLeft() + insets.left;
int rightPadding = getPaddingRight() + insets.right;
int topPadding = insets.top;
int bottomPadding = insets.bottom;
this.setPadding(leftPadding, topPadding, rightPadding, bottomPadding);
@SuppressLint("NewApi")
public void setFitsSysWindows(boolean b) {
if (Build.VERSION.SDK_INT >= 14) {
super.setFitsSystemWindows(b);
} else {
int topMargin = 0;
if (b) {
topMargin = getStatusBarHeight();
}
RelativeLayout.LayoutParams params = ((RelativeLayout.LayoutParams)mViewBehind.getLayoutParams());
int bottom = params.bottomMargin;
int left = params.leftMargin;
int right = params.rightMargin;
params.setMargins(left, topMargin, right, bottom);
}
}
private int getStatusBarHeight() {
if (mBarHeight >= 0) return mBarHeight;
DisplayMetrics displayMetrics = new DisplayMetrics();
((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics