From c7bf0fe5b687df0fc0e047b77729caf9645a100c Mon Sep 17 00:00:00 2001 From: Mohamed Shehab Date: Sun, 22 Mar 2015 14:39:22 +0100 Subject: [PATCH] - Fixing already attached to parent issue - Adding more example for different layouts - Renaming all view class to avoid confusion when creating the menu programmatically - Fixing the min. required SDK --- README.md | 12 +- library/build.gradle | 4 +- library/library.iml | 3 - ...tomView.java => DroppyMenuCustomItem.java} | 6 +- .../com/shehabic/droppy/DroppyMenuItem.java | 16 +- .../com/shehabic/droppy/DroppyMenuPopup.java | 26 +- .../shehabic/droppy/DroppyMenuSeparator.java | 2 +- ...iner.java => DroppyMenuContainerView.java} | 14 +- ...mIcon.java => DroppyMenuItemIconView.java} | 26 +- ...itle.java => DroppyMenuItemTitleView.java} | 26 +- ...yMenuItem.java => DroppyMenuItemView.java} | 32 +-- ...enuPopup.java => DroppyMenuPopupView.java} | 16 +- ...ator.java => DroppyMenuSeparatorView.java} | 16 +- library/src/main/res/values/droppy__attr.xml | 12 +- samples/build.gradle | 3 +- samples/src/main/AndroidManifest.xml | 25 +- .../droppy_samples/ActivityWithFragment.java | 133 ++++++++++ .../DefaultExampleActivity.java | 100 ++++++++ .../droppy_samples/FullscreenActivity.java | 228 ++++++++++++++++++ .../shehabic/droppy_samples/MainActivity.java | 8 +- .../droppy_samples/util/SystemUiHider.java | 172 +++++++++++++ .../util/SystemUiHiderBase.java | 63 +++++ .../util/SystemUiHiderHoneycomb.java | 141 +++++++++++ .../activity_activity_with_fragment.xml | 7 + .../main/res/layout/activity_fullscreen.xml | 54 +++++ samples/src/main/res/layout/activity_main.xml | 2 +- .../src/main/res/layout/activity_selector.xml | 12 + .../res/layout/fragment_activity_with.xml | 25 ++ samples/src/main/res/layout/item_layout.xml | 11 + samples/src/main/res/menu/droppy.xml | 2 +- .../src/main/res/menu/menu_activity_with.xml | 9 + samples/src/main/res/menu/menu_main.xml | 2 +- samples/src/main/res/values-v11/styles.xml | 15 ++ samples/src/main/res/values/attrs.xml | 12 + samples/src/main/res/values/colors.xml | 2 + samples/src/main/res/values/strings.xml | 6 + samples/src/main/res/values/styles.xml | 19 ++ 37 files changed, 1149 insertions(+), 113 deletions(-) rename library/src/main/java/com/shehabic/droppy/{DroppyMenuCustomView.java => DroppyMenuCustomItem.java} (78%) rename library/src/main/java/com/shehabic/droppy/views/{DroppyMenuContainer.java => DroppyMenuContainerView.java} (66%) rename library/src/main/java/com/shehabic/droppy/views/{DroppyMenuItemIcon.java => DroppyMenuItemIconView.java} (67%) rename library/src/main/java/com/shehabic/droppy/views/{DroppyMenuItemTitle.java => DroppyMenuItemTitleView.java} (65%) rename library/src/main/java/com/shehabic/droppy/views/{DroppyMenuItem.java => DroppyMenuItemView.java} (64%) rename library/src/main/java/com/shehabic/droppy/views/{DroppyMenuPopup.java => DroppyMenuPopupView.java} (72%) rename library/src/main/java/com/shehabic/droppy/views/{DroppyMenuSeparator.java => DroppyMenuSeparatorView.java} (75%) create mode 100644 samples/src/main/java/com/shehabic/droppy_samples/ActivityWithFragment.java create mode 100644 samples/src/main/java/com/shehabic/droppy_samples/DefaultExampleActivity.java create mode 100644 samples/src/main/java/com/shehabic/droppy_samples/FullscreenActivity.java create mode 100644 samples/src/main/java/com/shehabic/droppy_samples/util/SystemUiHider.java create mode 100644 samples/src/main/java/com/shehabic/droppy_samples/util/SystemUiHiderBase.java create mode 100644 samples/src/main/java/com/shehabic/droppy_samples/util/SystemUiHiderHoneycomb.java create mode 100644 samples/src/main/res/layout/activity_activity_with_fragment.xml create mode 100644 samples/src/main/res/layout/activity_fullscreen.xml create mode 100644 samples/src/main/res/layout/activity_selector.xml create mode 100644 samples/src/main/res/layout/fragment_activity_with.xml create mode 100644 samples/src/main/res/layout/item_layout.xml create mode 100644 samples/src/main/res/menu/menu_activity_with.xml create mode 100644 samples/src/main/res/values-v11/styles.xml create mode 100644 samples/src/main/res/values/attrs.xml diff --git a/README.md b/README.md index 073ec96..4c279ab 100644 --- a/README.md +++ b/README.md @@ -150,15 +150,23 @@ Why not the native PopupMenu? ============================= Well if you have struggled long enough trying to show an icon beside the text in the normal popup menu or wanted to created a simple popup with custom view yest still contextual to an exisitng view, you would've know that it was almost impossible to do with the normal popup menu unless you use reflection and hack a the internal properties for PopupMenu and yet just add extra icon but not a fully customized view. +Reporting Bug / Opening Issues +============================== + 1-Please first make sure the issue you're reporting doesn't already exists to avoid duplicates. + 2-Please make sure you specify enough info if possible, including Target and Minimum SDK used, and portion of the code in addition to the stack trace/error message in case of errors. + +Forks / Pull Request +==================== + As per the license you're free to fork the lib, and modify as you + Pull-request for enhancements and bug-fixes ar always welcomed + Developed By ============ - * Mohamed Shehab - License ======= - Copyright 2015 Mohamed Shehab Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/library/build.gradle b/library/build.gradle index 881a019..2a42a25 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -5,7 +5,7 @@ android { buildToolsVersion "21.1.2" defaultConfig { - minSdkVersion 14 + minSdkVersion 13 targetSdkVersion 21 versionCode 3 versionName "0.2.1" @@ -21,7 +21,7 @@ android { ext { PUBLISH_GROUP_ID = 'com.shehabic.droppy' PUBLISH_ARTIFACT_ID = 'Droppy' - PUBLISH_VERSION = '0.2.1' + PUBLISH_VERSION = '0.2.5' } diff --git a/library/library.iml b/library/library.iml index 31e8a15..6b11ca9 100644 --- a/library/library.iml +++ b/library/library.iml @@ -62,7 +62,6 @@ - @@ -82,9 +81,7 @@ - - diff --git a/library/src/main/java/com/shehabic/droppy/DroppyMenuCustomView.java b/library/src/main/java/com/shehabic/droppy/DroppyMenuCustomItem.java similarity index 78% rename from library/src/main/java/com/shehabic/droppy/DroppyMenuCustomView.java rename to library/src/main/java/com/shehabic/droppy/DroppyMenuCustomItem.java index 2f413e3..1c62527 100644 --- a/library/src/main/java/com/shehabic/droppy/DroppyMenuCustomView.java +++ b/library/src/main/java/com/shehabic/droppy/DroppyMenuCustomItem.java @@ -7,15 +7,15 @@ /** * Created by shehabic on 3/1/15. */ -public class DroppyMenuCustomView extends DroppyMenuItemAbstract { +public class DroppyMenuCustomItem extends DroppyMenuItemAbstract { - public DroppyMenuCustomView(int customResourceId){ + public DroppyMenuCustomItem(int customResourceId){ isClickable = false; type = TYPE_CUSTOM; customViewResourceId = customResourceId; } - public DroppyMenuCustomView(View customView){ + public DroppyMenuCustomItem(View customView){ isClickable = false; type = TYPE_CUSTOM; renderedView = customView; diff --git a/library/src/main/java/com/shehabic/droppy/DroppyMenuItem.java b/library/src/main/java/com/shehabic/droppy/DroppyMenuItem.java index 7eb8129..74f2093 100644 --- a/library/src/main/java/com/shehabic/droppy/DroppyMenuItem.java +++ b/library/src/main/java/com/shehabic/droppy/DroppyMenuItem.java @@ -3,11 +3,9 @@ import android.content.Context; import android.graphics.drawable.Drawable; import android.view.View; -import android.widget.ImageView; -import android.widget.TextView; -import com.shehabic.droppy.views.DroppyMenuItemIcon; -import com.shehabic.droppy.views.DroppyMenuItemTitle; +import com.shehabic.droppy.views.DroppyMenuItemIconView; +import com.shehabic.droppy.views.DroppyMenuItemTitleView; /** * Created by shehabic on 2/28/15. @@ -15,7 +13,7 @@ public class DroppyMenuItem extends DroppyMenuItemAbstract { private Drawable iconDrawable; - protected com.shehabic.droppy.views.DroppyMenuItem renderedView; + protected com.shehabic.droppy.views.DroppyMenuItemView renderedView; void initMenuItem(String title, int iconResourceId) { @@ -44,18 +42,18 @@ public void setIcon(Drawable iconDrawable) @Override public View render(Context context) { - renderedView = new com.shehabic.droppy.views.DroppyMenuItem(context); + renderedView = new com.shehabic.droppy.views.DroppyMenuItemView(context); if (this.icon != -1) { - DroppyMenuItemIcon droppyMenuItemIcon = new DroppyMenuItemIcon(context); + DroppyMenuItemIconView droppyMenuItemIcon = new DroppyMenuItemIconView(context); droppyMenuItemIcon.setImageResource(this.icon); } else if (this.iconDrawable != null) { - DroppyMenuItemIcon droppyMenuItemIcon = new DroppyMenuItemIcon(context); + DroppyMenuItemIconView droppyMenuItemIcon = new DroppyMenuItemIconView(context); droppyMenuItemIcon.setImageDrawable(iconDrawable); renderedView.addView(droppyMenuItemIcon); } - DroppyMenuItemTitle droppyMenuItemTitle = new DroppyMenuItemTitle(context); + DroppyMenuItemTitleView droppyMenuItemTitle = new DroppyMenuItemTitleView(context); droppyMenuItemTitle.setText(this.title); renderedView.addView(droppyMenuItemTitle); diff --git a/library/src/main/java/com/shehabic/droppy/DroppyMenuPopup.java b/library/src/main/java/com/shehabic/droppy/DroppyMenuPopup.java index b222a4a..0afa0c0 100644 --- a/library/src/main/java/com/shehabic/droppy/DroppyMenuPopup.java +++ b/library/src/main/java/com/shehabic/droppy/DroppyMenuPopup.java @@ -13,7 +13,7 @@ import android.view.WindowManager; import android.widget.FrameLayout; -import com.shehabic.droppy.views.DroppyMenuContainer; +import com.shehabic.droppy.views.DroppyMenuContainerView; import java.lang.reflect.Constructor; import java.util.ArrayList; @@ -27,8 +27,8 @@ public class DroppyMenuPopup { protected View anchor; protected List menuItems = new ArrayList(); protected View mContentView; - protected com.shehabic.droppy.views.DroppyMenuPopup mPopupView; - protected DroppyMenuContainer droppyMenuContainer; + protected com.shehabic.droppy.views.DroppyMenuPopupView mPopupView; + protected DroppyMenuContainerView droppyMenuContainer; protected DroppyClickCallbackInterface droppyClickCallbackInterface; protected int popupMenuLayoutResourceId; protected FrameLayout modalWindow; @@ -100,6 +100,7 @@ public void show() { FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); adjustDropDownPosition(lp, -20, 30); mContentView = new PopupViewContainer(mContext); + detachPopupView(); ((ViewGroup) mContentView).addView(mPopupView); mContentView.setFocusable(true); mContentView.setClickable(true); @@ -107,15 +108,22 @@ public void show() { mContentView.requestFocus(); } + protected void detachPopupView() + { + if (mPopupView.getParent() != null) { + try { + ((ViewGroup) mPopupView.getParent()).removeView(mPopupView); + } catch (Exception e) { + + } + } + } + public void dismiss() { ((ViewGroup) mContentView.getParent()).removeView(mContentView); ((ViewGroup) modalWindow.getParent()).removeView(modalWindow); } - public void notifyChange() { - render(true); - } - protected void render() { render(false); } @@ -125,8 +133,8 @@ protected void render(boolean forceRender) { if (mPopupView != null && ((ViewGroup) mPopupView).getChildCount() > 0) { ((ViewGroup) mPopupView).removeAllViews(); } - mPopupView = new com.shehabic.droppy.views.DroppyMenuPopup(mContext); - droppyMenuContainer = new DroppyMenuContainer(mContext); + mPopupView = new com.shehabic.droppy.views.DroppyMenuPopupView(mContext); + droppyMenuContainer = new DroppyMenuContainerView(mContext); mPopupView.addView(droppyMenuContainer); FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); mPopupView.setLayoutParams(lp); diff --git a/library/src/main/java/com/shehabic/droppy/DroppyMenuSeparator.java b/library/src/main/java/com/shehabic/droppy/DroppyMenuSeparator.java index f82a7d0..7aeb5d7 100644 --- a/library/src/main/java/com/shehabic/droppy/DroppyMenuSeparator.java +++ b/library/src/main/java/com/shehabic/droppy/DroppyMenuSeparator.java @@ -16,7 +16,7 @@ public DroppyMenuSeparator() { @Override public View render(Context context) { if (renderedView == null) { - renderedView = new com.shehabic.droppy.views.DroppyMenuSeparator(context); + renderedView = new com.shehabic.droppy.views.DroppyMenuSeparatorView(context); } return renderedView; diff --git a/library/src/main/java/com/shehabic/droppy/views/DroppyMenuContainer.java b/library/src/main/java/com/shehabic/droppy/views/DroppyMenuContainerView.java similarity index 66% rename from library/src/main/java/com/shehabic/droppy/views/DroppyMenuContainer.java rename to library/src/main/java/com/shehabic/droppy/views/DroppyMenuContainerView.java index bf71547..2b5e882 100644 --- a/library/src/main/java/com/shehabic/droppy/views/DroppyMenuContainer.java +++ b/library/src/main/java/com/shehabic/droppy/views/DroppyMenuContainerView.java @@ -11,23 +11,23 @@ /** * Created by shehabic on 3/6/15. */ -public class DroppyMenuContainer extends LinearLayout +public class DroppyMenuContainerView extends LinearLayout { - public DroppyMenuContainer(Context context) { + public DroppyMenuContainerView(Context context) { this(context, null); } - public DroppyMenuContainer(Context context, AttributeSet attrs) { + public DroppyMenuContainerView(Context context, AttributeSet attrs) { this(context, attrs, R.attr.droppyMenuStyle); } - public DroppyMenuContainer(Context context, AttributeSet attrs, int defStyleAttr) { + public DroppyMenuContainerView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); this.setOrientation(VERTICAL); - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DroppyMenuPopup, defStyleAttr, 0); + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DroppyMenuPopupView, defStyleAttr, 0); ViewGroup.LayoutParams lp = getLayoutParams(); - int height = a.getLayoutDimension(R.styleable.DroppyMenuContainer_android_layout_height, ViewGroup.LayoutParams.WRAP_CONTENT); - int width = a.getLayoutDimension(R.styleable.DroppyMenuContainer_android_layout_width, ViewGroup.LayoutParams.WRAP_CONTENT); + int height = a.getLayoutDimension(R.styleable.DroppyMenuContainerView_android_layout_height, ViewGroup.LayoutParams.WRAP_CONTENT); + int width = a.getLayoutDimension(R.styleable.DroppyMenuContainerView_android_layout_width, ViewGroup.LayoutParams.WRAP_CONTENT); if (lp == null) { lp = new ViewGroup.LayoutParams(width, height); diff --git a/library/src/main/java/com/shehabic/droppy/views/DroppyMenuItemIcon.java b/library/src/main/java/com/shehabic/droppy/views/DroppyMenuItemIconView.java similarity index 67% rename from library/src/main/java/com/shehabic/droppy/views/DroppyMenuItemIcon.java rename to library/src/main/java/com/shehabic/droppy/views/DroppyMenuItemIconView.java index f625f6a..6dac97d 100644 --- a/library/src/main/java/com/shehabic/droppy/views/DroppyMenuItemIcon.java +++ b/library/src/main/java/com/shehabic/droppy/views/DroppyMenuItemIconView.java @@ -13,17 +13,17 @@ /** * Created by shehabic on 3/7/15. */ -public class DroppyMenuItemIcon extends ImageView { +public class DroppyMenuItemIconView extends ImageView { - public DroppyMenuItemIcon(Context context) { + public DroppyMenuItemIconView(Context context) { this(context, null); } - public DroppyMenuItemIcon(Context context, AttributeSet attrs) { + public DroppyMenuItemIconView(Context context, AttributeSet attrs) { this(context, attrs, R.attr.droppyMenuItemIconStyle); } - public DroppyMenuItemIcon(Context context, AttributeSet attrs, int defStyleAttr) { + public DroppyMenuItemIconView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); final int defaultMaxWidth = (int) getResources().getDimension(R.dimen.default_menu_item_icon_maxWidth); @@ -33,19 +33,19 @@ public DroppyMenuItemIcon(Context context, AttributeSet attrs, int defStyleAttr) final int defaultMarginLeft = (int) getResources().getDimension(R.dimen.default_menu_item_icon_marginLeft); final int defaultMarginRight= (int) getResources().getDimension(R.dimen.default_menu_item_icon_marginRight); - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DroppyMenuItemIcon, defStyleAttr, 0); - int maxWidth = (int) a.getDimension(R.styleable.DroppyMenuItemIcon_android_maxWidth, defaultMaxWidth); - int maxHeight = (int) a.getDimension(R.styleable.DroppyMenuItemIcon_android_maxHeight, defaultMaxHeight); - int width = a.getLayoutDimension(R.styleable.DroppyMenuItemIcon_android_layout_width, ViewGroup.LayoutParams.WRAP_CONTENT); - int height = a.getLayoutDimension(R.styleable.DroppyMenuItemIcon_android_layout_height, ViewGroup.LayoutParams.WRAP_CONTENT); + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DroppyMenuItemIconView, defStyleAttr, 0); + int maxWidth = (int) a.getDimension(R.styleable.DroppyMenuItemIconView_android_maxWidth, defaultMaxWidth); + int maxHeight = (int) a.getDimension(R.styleable.DroppyMenuItemIconView_android_maxHeight, defaultMaxHeight); + int width = a.getLayoutDimension(R.styleable.DroppyMenuItemIconView_android_layout_width, ViewGroup.LayoutParams.WRAP_CONTENT); + int height = a.getLayoutDimension(R.styleable.DroppyMenuItemIconView_android_layout_height, ViewGroup.LayoutParams.WRAP_CONTENT); LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(width, height); - lp.rightMargin = a.getDimensionPixelSize(R.styleable.DroppyMenuItemIcon_android_layout_marginRight, defaultMarginRight); - lp.leftMargin = a.getDimensionPixelSize(R.styleable.DroppyMenuItemIcon_android_layout_marginLeft, defaultMarginLeft); + lp.rightMargin = a.getDimensionPixelSize(R.styleable.DroppyMenuItemIconView_android_layout_marginRight, defaultMarginRight); + lp.leftMargin = a.getDimensionPixelSize(R.styleable.DroppyMenuItemIconView_android_layout_marginLeft, defaultMarginLeft); lp.width = width; lp.height = height; - lp.weight = a.getFloat(R.styleable.DroppyMenuItemIcon_android_layout_weight, defaultWeight); - lp.gravity = a.getInteger(R.styleable.DroppyMenuItemIcon_android_layout_gravity, defaultLayoutGravity); + lp.weight = a.getFloat(R.styleable.DroppyMenuItemIconView_android_layout_weight, defaultWeight); + lp.gravity = a.getInteger(R.styleable.DroppyMenuItemIconView_android_layout_gravity, defaultLayoutGravity); setMaxHeight(maxWidth); setMaxHeight(maxHeight); diff --git a/library/src/main/java/com/shehabic/droppy/views/DroppyMenuItemTitle.java b/library/src/main/java/com/shehabic/droppy/views/DroppyMenuItemTitleView.java similarity index 65% rename from library/src/main/java/com/shehabic/droppy/views/DroppyMenuItemTitle.java rename to library/src/main/java/com/shehabic/droppy/views/DroppyMenuItemTitleView.java index 2363fab..186d936 100644 --- a/library/src/main/java/com/shehabic/droppy/views/DroppyMenuItemTitle.java +++ b/library/src/main/java/com/shehabic/droppy/views/DroppyMenuItemTitleView.java @@ -13,17 +13,17 @@ /** * Created by shehabic on 3/7/15. */ -public class DroppyMenuItemTitle extends TextView { +public class DroppyMenuItemTitleView extends TextView { - public DroppyMenuItemTitle(Context context) { + public DroppyMenuItemTitleView(Context context) { this(context, null); } - public DroppyMenuItemTitle(Context context, AttributeSet attrs) { + public DroppyMenuItemTitleView(Context context, AttributeSet attrs) { this(context, attrs, R.attr.droppyMenuItemTitleStyle); } - public DroppyMenuItemTitle(Context context, AttributeSet attrs, int defStyleAttr) { + public DroppyMenuItemTitleView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); final int defaultWidth = ViewGroup.LayoutParams.MATCH_PARENT; @@ -34,20 +34,20 @@ public DroppyMenuItemTitle(Context context, AttributeSet attrs, int defStyleAttr final int defaultGravity = Gravity.CENTER_VERTICAL; final int defaultLayoutGravity = Gravity.END | Gravity.CENTER_VERTICAL; - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DroppyMenuItemTitle, defStyleAttr, 0); - int minWidth = (int) a.getDimension(R.styleable.DroppyMenuItemTitle_android_minWidth, defaultMinWidth); - int minHeight = (int) a.getDimension(R.styleable.DroppyMenuItemTitle_android_minHeight, defaultMinHeight); - int width = a.getLayoutDimension(R.styleable.DroppyMenuItemTitle_android_layout_width, defaultWidth); - int height = a.getLayoutDimension(R.styleable.DroppyMenuItemTitle_android_layout_height, ViewGroup.LayoutParams.WRAP_CONTENT); - int color = a.getColor(R.styleable.DroppyMenuItemTitle_android_textColor, defaultColor); + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DroppyMenuItemTitleView, defStyleAttr, 0); + int minWidth = (int) a.getDimension(R.styleable.DroppyMenuItemTitleView_android_minWidth, defaultMinWidth); + int minHeight = (int) a.getDimension(R.styleable.DroppyMenuItemTitleView_android_minHeight, defaultMinHeight); + int width = a.getLayoutDimension(R.styleable.DroppyMenuItemTitleView_android_layout_width, defaultWidth); + int height = a.getLayoutDimension(R.styleable.DroppyMenuItemTitleView_android_layout_height, ViewGroup.LayoutParams.WRAP_CONTENT); + int color = a.getColor(R.styleable.DroppyMenuItemTitleView_android_textColor, defaultColor); - setGravity(a.getInt(R.styleable.DroppyMenuItemTitle_android_gravity, defaultGravity)); + setGravity(a.getInt(R.styleable.DroppyMenuItemTitleView_android_gravity, defaultGravity)); LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(width, height); lp.width = width; lp.height = height; - lp.weight = a.getFloat(R.styleable.DroppyMenuItemTitle_android_layout_weight, defaultWeight); - lp.gravity = a.getInteger(R.styleable.DroppyMenuItemTitle_android_layout_gravity, defaultLayoutGravity); + lp.weight = a.getFloat(R.styleable.DroppyMenuItemTitleView_android_layout_weight, defaultWeight); + lp.gravity = a.getInteger(R.styleable.DroppyMenuItemTitleView_android_layout_gravity, defaultLayoutGravity); setLayoutParams(lp); setMinHeight(minWidth); diff --git a/library/src/main/java/com/shehabic/droppy/views/DroppyMenuItem.java b/library/src/main/java/com/shehabic/droppy/views/DroppyMenuItemView.java similarity index 64% rename from library/src/main/java/com/shehabic/droppy/views/DroppyMenuItem.java rename to library/src/main/java/com/shehabic/droppy/views/DroppyMenuItemView.java index abc59b1..d4b054c 100644 --- a/library/src/main/java/com/shehabic/droppy/views/DroppyMenuItem.java +++ b/library/src/main/java/com/shehabic/droppy/views/DroppyMenuItemView.java @@ -13,50 +13,50 @@ /** * Created by shehabic on 3/7/15. */ -public class DroppyMenuItem extends LinearLayout { +public class DroppyMenuItemView extends LinearLayout { - public DroppyMenuItem(Context context) { + public DroppyMenuItemView(Context context) { this(context, null); } - public DroppyMenuItem(Context context, AttributeSet attrs) { + public DroppyMenuItemView(Context context, AttributeSet attrs) { this(context, attrs, R.attr.droppyMenuItemStyle); } - public DroppyMenuItem(Context context, AttributeSet attrs, int defStyleAttr) { + public DroppyMenuItemView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DroppyMenuItem, defStyleAttr, 0); + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DroppyMenuItemView, defStyleAttr, 0); final Drawable defaultDrawable = getResources().getDrawable(R.drawable.default_menu_item_background); final float defaultMinWidth = getResources().getDimension(R.dimen.default_menu_item_minWidth); final float defaultMinHeight = getResources().getDimension(R.dimen.default_menu_item_minHeight); final boolean defaultIsClickable = getResources().getBoolean(R.bool.default_menu_item_clickable); - float minWidth = a.getDimension(R.styleable.DroppyMenuItem_android_minWidth, defaultMinWidth); - float minHeight = a.getDimension(R.styleable.DroppyMenuItem_android_minHeight, defaultMinHeight); + float minWidth = a.getDimension(R.styleable.DroppyMenuItemView_android_minWidth, defaultMinWidth); + float minHeight = a.getDimension(R.styleable.DroppyMenuItemView_android_minHeight, defaultMinHeight); ViewGroup.LayoutParams lp = getLayoutParams(); setMinimumWidth((int) minWidth); setMinimumHeight((int) minHeight); - int width = a.getLayoutDimension(R.styleable.DroppyMenuItem_android_layout_width, ViewGroup.LayoutParams.MATCH_PARENT); - int height = a.getLayoutDimension(R.styleable.DroppyMenuItem_android_layout_height, ViewGroup.LayoutParams.WRAP_CONTENT); + int width = a.getLayoutDimension(R.styleable.DroppyMenuItemView_android_layout_width, ViewGroup.LayoutParams.MATCH_PARENT); + int height = a.getLayoutDimension(R.styleable.DroppyMenuItemView_android_layout_height, ViewGroup.LayoutParams.WRAP_CONTENT); if (lp == null) { lp = new ViewGroup.LayoutParams(width, height); } else { lp.width = width; lp.height = height; } - setClickable(a.getBoolean(R.styleable.DroppyMenuItem_android_clickable, defaultIsClickable)); + setClickable(a.getBoolean(R.styleable.DroppyMenuItemView_android_clickable, defaultIsClickable)); setOrientation(LinearLayout.HORIZONTAL); - setGravity(a.getInteger(R.styleable.DroppyMenuItem_android_gravity, Gravity.CENTER_VERTICAL)); - int paddingTop = (int) a.getDimension(R.styleable.DroppyMenuItem_android_paddingTop, (int) getResources().getDimension(R.dimen.default_menu_item_paddingTop)); - int paddingBottom = (int) a.getDimension(R.styleable.DroppyMenuItem_android_paddingBottom, (int) getResources().getDimension(R.dimen.default_menu_item_paddingBottom)); - int paddingLeft = (int) a.getDimension(R.styleable.DroppyMenuItem_android_paddingLeft, (int) getResources().getDimension(R.dimen.default_menu_item_paddingLeft)); - int paddingRight = (int) a.getDimension(R.styleable.DroppyMenuItem_android_paddingRight, (int) getResources().getDimension(R.dimen.default_menu_item_paddingRight)); + setGravity(a.getInteger(R.styleable.DroppyMenuItemView_android_gravity, Gravity.CENTER_VERTICAL)); + int paddingTop = (int) a.getDimension(R.styleable.DroppyMenuItemView_android_paddingTop, (int) getResources().getDimension(R.dimen.default_menu_item_paddingTop)); + int paddingBottom = (int) a.getDimension(R.styleable.DroppyMenuItemView_android_paddingBottom, (int) getResources().getDimension(R.dimen.default_menu_item_paddingBottom)); + int paddingLeft = (int) a.getDimension(R.styleable.DroppyMenuItemView_android_paddingLeft, (int) getResources().getDimension(R.dimen.default_menu_item_paddingLeft)); + int paddingRight = (int) a.getDimension(R.styleable.DroppyMenuItemView_android_paddingRight, (int) getResources().getDimension(R.dimen.default_menu_item_paddingRight)); setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom); - Drawable background = a.getDrawable(R.styleable.DroppyMenuItem_android_background); + Drawable background = a.getDrawable(R.styleable.DroppyMenuItemView_android_background); if (background != null) { setBackgroundDrawable(background); } else { diff --git a/library/src/main/java/com/shehabic/droppy/views/DroppyMenuPopup.java b/library/src/main/java/com/shehabic/droppy/views/DroppyMenuPopupView.java similarity index 72% rename from library/src/main/java/com/shehabic/droppy/views/DroppyMenuPopup.java rename to library/src/main/java/com/shehabic/droppy/views/DroppyMenuPopupView.java index b5497a4..07e3888 100644 --- a/library/src/main/java/com/shehabic/droppy/views/DroppyMenuPopup.java +++ b/library/src/main/java/com/shehabic/droppy/views/DroppyMenuPopupView.java @@ -12,24 +12,24 @@ /** * Created by shehabic on 3/6/15. */ -public class DroppyMenuPopup extends FrameLayout +public class DroppyMenuPopupView extends FrameLayout { - public DroppyMenuPopup(Context context) { + public DroppyMenuPopupView(Context context) { this(context, null); } - public DroppyMenuPopup(Context context, AttributeSet attrs) { + public DroppyMenuPopupView(Context context, AttributeSet attrs) { this(context, attrs, R.attr.droppyPopupStyle); } - public DroppyMenuPopup(Context context, AttributeSet attrs, int defStyleAttr) { + public DroppyMenuPopupView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); final Drawable defaultDrawable = getResources().getDrawable(R.drawable.default_popup_background); - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DroppyMenuPopup, defStyleAttr, 0); - Drawable background = a.getDrawable(R.styleable.DroppyMenuPopup_android_background); - int height = a.getLayoutDimension(R.styleable.DroppyMenuPopup_android_layout_height, ViewGroup.LayoutParams.WRAP_CONTENT); - int width = a.getLayoutDimension(R.styleable.DroppyMenuPopup_android_layout_width, ViewGroup.LayoutParams.WRAP_CONTENT); + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DroppyMenuPopupView, defStyleAttr, 0); + Drawable background = a.getDrawable(R.styleable.DroppyMenuPopupView_android_background); + int height = a.getLayoutDimension(R.styleable.DroppyMenuPopupView_android_layout_height, ViewGroup.LayoutParams.WRAP_CONTENT); + int width = a.getLayoutDimension(R.styleable.DroppyMenuPopupView_android_layout_width, ViewGroup.LayoutParams.WRAP_CONTENT); ViewGroup.LayoutParams lp = getLayoutParams(); if (lp == null) { lp = new ViewGroup.LayoutParams(width, height); diff --git a/library/src/main/java/com/shehabic/droppy/views/DroppyMenuSeparator.java b/library/src/main/java/com/shehabic/droppy/views/DroppyMenuSeparatorView.java similarity index 75% rename from library/src/main/java/com/shehabic/droppy/views/DroppyMenuSeparator.java rename to library/src/main/java/com/shehabic/droppy/views/DroppyMenuSeparatorView.java index 7199ebf..25e534a 100644 --- a/library/src/main/java/com/shehabic/droppy/views/DroppyMenuSeparator.java +++ b/library/src/main/java/com/shehabic/droppy/views/DroppyMenuSeparatorView.java @@ -12,25 +12,25 @@ /** * Created by shehabic on 3/8/15. */ -public class DroppyMenuSeparator extends LinearLayout { - public DroppyMenuSeparator(Context context) { +public class DroppyMenuSeparatorView extends LinearLayout { + public DroppyMenuSeparatorView(Context context) { this(context, null); } - public DroppyMenuSeparator(Context context, AttributeSet attrs) { + public DroppyMenuSeparatorView(Context context, AttributeSet attrs) { this(context, attrs, R.attr.droppyMenuSeparatorStyle); } - public DroppyMenuSeparator(Context context, AttributeSet attrs, int defStyleAttr) { + public DroppyMenuSeparatorView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DroppyMenuItem, defStyleAttr, 0); + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DroppyMenuItemView, defStyleAttr, 0); final Drawable defaultSeparatorBackground = getResources().getDrawable(R.drawable.droppy_separator_background); final int defaultHeight = getResources().getDimensionPixelSize(R.dimen.default_menu_separator_height); ViewGroup.LayoutParams lp = getLayoutParams(); - int width = a.getLayoutDimension(R.styleable.DroppyMenuItem_android_layout_width, ViewGroup.LayoutParams.MATCH_PARENT); - int height = a.getLayoutDimension(R.styleable.DroppyMenuItem_android_layout_height, defaultHeight); + int width = a.getLayoutDimension(R.styleable.DroppyMenuItemView_android_layout_width, ViewGroup.LayoutParams.MATCH_PARENT); + int height = a.getLayoutDimension(R.styleable.DroppyMenuItemView_android_layout_height, defaultHeight); if (lp == null) { lp = new ViewGroup.LayoutParams(width, height); } else { @@ -39,7 +39,7 @@ public DroppyMenuSeparator(Context context, AttributeSet attrs, int defStyleAttr } setOrientation(LinearLayout.HORIZONTAL); - Drawable background = a.getDrawable(R.styleable.DroppyMenuSeparator_android_background); + Drawable background = a.getDrawable(R.styleable.DroppyMenuSeparatorView_android_background); if (background != null) { setBackgroundDrawable(background); } else { diff --git a/library/src/main/res/values/droppy__attr.xml b/library/src/main/res/values/droppy__attr.xml index b69ac56..f33cf5f 100644 --- a/library/src/main/res/values/droppy__attr.xml +++ b/library/src/main/res/values/droppy__attr.xml @@ -9,19 +9,19 @@ - + - + - + @@ -30,7 +30,7 @@ - + @@ -45,7 +45,7 @@ - + @@ -56,7 +56,7 @@ - + diff --git a/samples/build.gradle b/samples/build.gradle index eb329d2..41086b2 100644 --- a/samples/build.gradle +++ b/samples/build.gradle @@ -21,6 +21,7 @@ android { dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) - compile 'com.android.support:appcompat-v7:21.0.3' compile project(':library') + compile 'com.android.support:appcompat-v7:21.0.3' + compile 'com.android.support:support-v4:21.0.3' } diff --git a/samples/src/main/AndroidManifest.xml b/samples/src/main/AndroidManifest.xml index 7c3daef..1e77deb 100644 --- a/samples/src/main/AndroidManifest.xml +++ b/samples/src/main/AndroidManifest.xml @@ -1,20 +1,33 @@ + package="com.shehabic.droppy_samples"> + android:theme="@style/AppTheme"> + + + + + + + android:label="startup_activity"> - - + + - diff --git a/samples/src/main/java/com/shehabic/droppy_samples/ActivityWithFragment.java b/samples/src/main/java/com/shehabic/droppy_samples/ActivityWithFragment.java new file mode 100644 index 0000000..1c9010a --- /dev/null +++ b/samples/src/main/java/com/shehabic/droppy_samples/ActivityWithFragment.java @@ -0,0 +1,133 @@ +package com.shehabic.droppy_samples; + +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.Fragment; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.SeekBar; + +import com.shehabic.droppy.DroppyClickCallbackInterface; +import com.shehabic.droppy.DroppyMenuCustomItem; +import com.shehabic.droppy.DroppyMenuItem; +import com.shehabic.droppy.DroppyMenuPopup; + + +public class ActivityWithFragment extends FragmentActivity { + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_activity_with_fragment); + if (savedInstanceState == null) { + getSupportFragmentManager().beginTransaction() + .add(R.id.container, new PlaceholderFragment()) + .commit(); + } + } + + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.menu_activity_with, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + int id = item.getItemId(); + + //noinspection SimplifiableIfStatement + if (id == R.id.action_settings) { + return true; + } + + return super.onOptionsItemSelected(item); + } + + /** + * A placeholder fragment containing a simple view. + */ + public static class PlaceholderFragment extends Fragment { + + DroppyMenuPopup droppyMenu; + Button btn; + int seekbarValue = 0; + + + public PlaceholderFragment() { + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View rootView = inflater.inflate(R.layout.fragment_activity_with, container, false); + initButtons(rootView); + return rootView; + } + + protected void initButtons(View rootView) + { + btn = (Button) rootView.findViewById(R.id.menuButton); + btn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + initDroppyMenu(btn); + showDroppyMenu(); + } + }); + } + + private void initDroppyMenu(Button btn) + { + DroppyMenuPopup.Builder droppyBuilder = new DroppyMenuPopup.Builder(btn.getContext(), btn); + droppyBuilder.addMenuItem(new DroppyMenuItem("test1")) + .addMenuItem(new DroppyMenuItem("test2")) + .addSeparator() + .addMenuItem(new DroppyMenuItem("test3", R.drawable.ic_launcher)) + .triggerOnAnchorClick(false); + + DroppyMenuCustomItem sBarItem = new DroppyMenuCustomItem(R.layout.slider); + droppyBuilder.addMenuItem(sBarItem); + + droppyBuilder.setOnClick(new DroppyClickCallbackInterface() { + @Override + public void call(View v, int id) { + Log.d("Clicked on ", String.valueOf(id)); + } + }); + droppyMenu = droppyBuilder.build(); + } + + protected void showDroppyMenu() + { + droppyMenu.show(); + SeekBar sBar = (SeekBar) droppyMenu.getMenuView().findViewById(R.id.seekBar1); + sBar.setProgress(seekbarValue); + sBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + seekbarValue = progress; + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + } + }); + } + } +} diff --git a/samples/src/main/java/com/shehabic/droppy_samples/DefaultExampleActivity.java b/samples/src/main/java/com/shehabic/droppy_samples/DefaultExampleActivity.java new file mode 100644 index 0000000..bcde66b --- /dev/null +++ b/samples/src/main/java/com/shehabic/droppy_samples/DefaultExampleActivity.java @@ -0,0 +1,100 @@ +package com.shehabic.droppy_samples; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.LayoutInflater; + +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.BaseAdapter; + +import android.widget.ListView; + +import android.widget.TextView; +import java.util.ArrayList; +import java.util.List; + + +public class DefaultExampleActivity + + extends Activity { + + protected ListView listView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_selector); + initListView(); + } + + private void initListView() { + listView = (ListView) findViewById(R.id.activity_selector); + final List classes = new ArrayList<>(); + final List items = new ArrayList<>(); + classes.add(MainActivity.class); + items.add("ActionBar Normal Activity"); + + classes.add(ActivityWithFragment.class); + items.add("Fragment Activity"); + + classes.add(FullscreenActivity.class); + items.add("Fullscreen Activity"); + + ActivitySelectorAdapter adapter = new ActivitySelectorAdapter(this, items); + listView.setAdapter(adapter); + listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + Intent i = new Intent(DefaultExampleActivity.this, classes.get(position)); + startActivity(i); + } + }); + } + + class ActivitySelectorAdapter extends BaseAdapter + { + protected List items; + protected Context ctx; + + public ActivitySelectorAdapter(Context ctx, List items) + { + this.ctx = ctx; + this.items = items; + } + + @Override + public int getCount() { + return items.size(); + } + + @Override + public Object getItem(int position) { + return items.get(position); + } + + @Override + public long getItemId(int position) { + return (long) position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + if (convertView == null) { + // inflate the layout + LayoutInflater inflater = ((Activity) ctx).getLayoutInflater(); + convertView = inflater.inflate(android.R.layout.simple_list_item_2, parent, false); + } + + TextView textViewItem = (TextView) convertView.findViewById(android.R.id.text1); + textViewItem.setText(items.get(position)); + textViewItem.setTag(getItemId(position)); + + return convertView; + } + } +} + diff --git a/samples/src/main/java/com/shehabic/droppy_samples/FullscreenActivity.java b/samples/src/main/java/com/shehabic/droppy_samples/FullscreenActivity.java new file mode 100644 index 0000000..d3e0d06 --- /dev/null +++ b/samples/src/main/java/com/shehabic/droppy_samples/FullscreenActivity.java @@ -0,0 +1,228 @@ +package com.shehabic.droppy_samples; + +import com.shehabic.droppy.DroppyClickCallbackInterface; +import com.shehabic.droppy.DroppyMenuCustomItem; +import com.shehabic.droppy.DroppyMenuItem; +import com.shehabic.droppy.DroppyMenuPopup; +import com.shehabic.droppy_samples.util.SystemUiHider; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; +import android.widget.Button; +import android.widget.SeekBar; + + +/** + * An example full-screen activity that shows and hides the system UI (i.e. + * status bar and navigation/system bar) with user interaction. + * + * @see SystemUiHider + */ +public class FullscreenActivity extends Activity { + + DroppyMenuPopup droppyMenu; + Button btn; + int seekbarValue = 0; + + /** + * Whether or not the system UI should be auto-hidden after + * {@link #AUTO_HIDE_DELAY_MILLIS} milliseconds. + */ + private static final boolean AUTO_HIDE = true; + + /** + * If {@link #AUTO_HIDE} is set, the number of milliseconds to wait after + * user interaction before hiding the system UI. + */ + private static final int AUTO_HIDE_DELAY_MILLIS = 3000; + + /** + * If set, will toggle the system UI visibility upon interaction. Otherwise, + * will show the system UI visibility upon interaction. + */ + private static final boolean TOGGLE_ON_CLICK = true; + + /** + * The flags to pass to {@link SystemUiHider#getInstance}. + */ + private static final int HIDER_FLAGS = SystemUiHider.FLAG_HIDE_NAVIGATION; + + /** + * The instance of the {@link SystemUiHider} for this activity. + */ + private SystemUiHider mSystemUiHider; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_fullscreen); + + final View controlsView = findViewById(R.id.fullscreen_content_controls); + final View contentView = findViewById(R.id.fullscreen_content); + + // Set up an instance of SystemUiHider to control the system UI for + // this activity. + mSystemUiHider = SystemUiHider.getInstance(this, contentView, HIDER_FLAGS); + mSystemUiHider.setup(); + mSystemUiHider + .setOnVisibilityChangeListener(new SystemUiHider.OnVisibilityChangeListener() { + // Cached values. + int mControlsHeight; + int mShortAnimTime; + + @Override + @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2) + public void onVisibilityChange(boolean visible) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) { + // If the ViewPropertyAnimator API is available + // (Honeycomb MR2 and later), use it to animate the + // in-layout UI controls at the bottom of the + // screen. + if (mControlsHeight == 0) { + mControlsHeight = controlsView.getHeight(); + } + if (mShortAnimTime == 0) { + mShortAnimTime = getResources().getInteger( + android.R.integer.config_shortAnimTime); + } + controlsView.animate() + .translationY(visible ? 0 : mControlsHeight) + .setDuration(mShortAnimTime); + } else { + // If the ViewPropertyAnimator APIs aren't + // available, simply show or hide the in-layout UI + // controls. + controlsView.setVisibility(visible ? View.VISIBLE : View.GONE); + } + + if (visible && AUTO_HIDE) { + // Schedule a hide(). + delayedHide(AUTO_HIDE_DELAY_MILLIS); + } + } + }); + + // Set up the user interaction to manually show or hide the system UI. + contentView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (TOGGLE_ON_CLICK) { + mSystemUiHider.toggle(); + } else { + mSystemUiHider.show(); + } + } + }); + + // Upon interacting with UI controls, delay any scheduled hide() + // operations to prevent the jarring behavior of controls going away + // while interacting with the UI. + findViewById(R.id.dummy_button).setOnTouchListener(mDelayHideTouchListener); + initButtons(); + } + + @Override + protected void onPostCreate(Bundle savedInstanceState) { + super.onPostCreate(savedInstanceState); + + // Trigger the initial hide() shortly after the activity has been + // created, to briefly hint to the user that UI controls + // are available. + delayedHide(100); + } + + + /** + * Touch listener to use for in-layout UI controls to delay hiding the + * system UI. This is to prevent the jarring behavior of controls going away + * while interacting with activity UI. + */ + View.OnTouchListener mDelayHideTouchListener = new View.OnTouchListener() { + @Override + public boolean onTouch(View view, MotionEvent motionEvent) { + if (AUTO_HIDE) { + delayedHide(AUTO_HIDE_DELAY_MILLIS); + } + return false; + } + }; + + Handler mHideHandler = new Handler(); + Runnable mHideRunnable = new Runnable() { + @Override + public void run() { + mSystemUiHider.hide(); + } + }; + + /** + * Schedules a call to hide() in [delay] milliseconds, canceling any + * previously scheduled calls. + */ + private void delayedHide(int delayMillis) { + mHideHandler.removeCallbacks(mHideRunnable); + mHideHandler.postDelayed(mHideRunnable, delayMillis); + } + + protected void initButtons() + { + btn = (Button) findViewById(R.id.menuButton); + btn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + initDroppyMenu(btn); + showDroppyMenu(); + } + }); + } + + private void initDroppyMenu(Button btn) + { + DroppyMenuPopup.Builder droppyBuilder = new DroppyMenuPopup.Builder(this, btn); + droppyBuilder.addMenuItem(new DroppyMenuItem("test1")) + .addMenuItem(new DroppyMenuItem("test2")) + .addSeparator() + .addMenuItem(new DroppyMenuItem("test3", R.drawable.ic_launcher)) + .triggerOnAnchorClick(false); + + DroppyMenuCustomItem sBarItem = new DroppyMenuCustomItem(R.layout.slider); + droppyBuilder.addMenuItem(sBarItem); + + droppyBuilder.setOnClick(new DroppyClickCallbackInterface() { + @Override + public void call(View v, int id) { + Log.d("Clicked on ", String.valueOf(id)); + } + }); + droppyMenu = droppyBuilder.build(); + } + + protected void showDroppyMenu() + { + droppyMenu.show(); + SeekBar sBar = (SeekBar) droppyMenu.getMenuView().findViewById(R.id.seekBar1); + sBar.setProgress(seekbarValue); + sBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + seekbarValue = progress; + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + } + }); + } + +} diff --git a/samples/src/main/java/com/shehabic/droppy_samples/MainActivity.java b/samples/src/main/java/com/shehabic/droppy_samples/MainActivity.java index 301e2c0..0b9c9d3 100644 --- a/samples/src/main/java/com/shehabic/droppy_samples/MainActivity.java +++ b/samples/src/main/java/com/shehabic/droppy_samples/MainActivity.java @@ -10,10 +10,13 @@ import android.widget.SeekBar; import com.shehabic.droppy.DroppyClickCallbackInterface; +import com.shehabic.droppy.DroppyMenuCustomItem; import com.shehabic.droppy.DroppyMenuPopup; -import com.shehabic.droppy.DroppyMenuCustomView; import com.shehabic.droppy.DroppyMenuItem; +/** + * Created by shehabic on 3/21/15. + */ public class MainActivity extends ActionBarActivity { DroppyMenuPopup droppyMenu; @@ -84,7 +87,7 @@ private void initDroppyMenu(Button btn) .addMenuItem(new DroppyMenuItem("test3", R.drawable.ic_launcher)) .triggerOnAnchorClick(false); - DroppyMenuCustomView sBarItem = new DroppyMenuCustomView(R.layout.slider); + DroppyMenuCustomItem sBarItem = new DroppyMenuCustomItem(R.layout.slider); droppyBuilder.addMenuItem(sBarItem); droppyBuilder.setOnClick(new DroppyClickCallbackInterface() { @@ -133,4 +136,3 @@ public boolean onOptionsItemSelected(MenuItem item) { return super.onOptionsItemSelected(item); } } - diff --git a/samples/src/main/java/com/shehabic/droppy_samples/util/SystemUiHider.java b/samples/src/main/java/com/shehabic/droppy_samples/util/SystemUiHider.java new file mode 100644 index 0000000..b2ff553 --- /dev/null +++ b/samples/src/main/java/com/shehabic/droppy_samples/util/SystemUiHider.java @@ -0,0 +1,172 @@ +package com.shehabic.droppy_samples.util; + +import android.app.Activity; +import android.os.Build; +import android.view.View; + +/** + * A utility class that helps with showing and hiding system UI such as the + * status bar and navigation/system bar. This class uses backward-compatibility + * techniques described in + * Creating Backward-Compatible UIs to ensure that devices running any + * version of ndroid OS are supported. More specifically, there are separate + * implementations of this abstract class: for newer devices, + * {@link #getInstance} will return a {@link SystemUiHiderHoneycomb} instance, + * while on older devices {@link #getInstance} will return a + * {@link SystemUiHiderBase} instance. + *

+ * For more on system bars, see System Bars. + * + * @see android.view.View#setSystemUiVisibility(int) + * @see android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN + */ +public abstract class SystemUiHider { + /** + * When this flag is set, the + * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN} + * flag will be set on older devices, making the status bar "float" on top + * of the activity layout. This is most useful when there are no controls at + * the top of the activity layout. + *

+ * This flag isn't used on newer devices because the action + * bar, the most important structural element of an Android app, should + * be visible and not obscured by the system UI. + */ + public static final int FLAG_LAYOUT_IN_SCREEN_OLDER_DEVICES = 0x1; + + /** + * When this flag is set, {@link #show()} and {@link #hide()} will toggle + * the visibility of the status bar. If there is a navigation bar, show and + * hide will toggle low profile mode. + */ + public static final int FLAG_FULLSCREEN = 0x2; + + /** + * When this flag is set, {@link #show()} and {@link #hide()} will toggle + * the visibility of the navigation bar, if it's present on the device and + * the device allows hiding it. In cases where the navigation bar is present + * but cannot be hidden, show and hide will toggle low profile mode. + */ + public static final int FLAG_HIDE_NAVIGATION = FLAG_FULLSCREEN | 0x4; + + /** + * The activity associated with this UI hider object. + */ + protected Activity mActivity; + + /** + * The view on which {@link View#setSystemUiVisibility(int)} will be called. + */ + protected View mAnchorView; + + /** + * The current UI hider flags. + * + * @see #FLAG_FULLSCREEN + * @see #FLAG_HIDE_NAVIGATION + * @see #FLAG_LAYOUT_IN_SCREEN_OLDER_DEVICES + */ + protected int mFlags; + + /** + * The current visibility callback. + */ + protected OnVisibilityChangeListener mOnVisibilityChangeListener = sDummyListener; + + /** + * Creates and returns an instance of {@link SystemUiHider} that is + * appropriate for this device. The object will be either a + * {@link SystemUiHiderBase} or {@link SystemUiHiderHoneycomb} depending on + * the device. + * + * @param activity The activity whose window's system UI should be + * controlled by this class. + * @param anchorView The view on which + * {@link View#setSystemUiVisibility(int)} will be called. + * @param flags Either 0 or any combination of {@link #FLAG_FULLSCREEN}, + * {@link #FLAG_HIDE_NAVIGATION}, and + * {@link #FLAG_LAYOUT_IN_SCREEN_OLDER_DEVICES}. + */ + public static SystemUiHider getInstance(Activity activity, View anchorView, int flags) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + return new SystemUiHiderHoneycomb(activity, anchorView, flags); + } else { + return new SystemUiHiderBase(activity, anchorView, flags); + } + } + + protected SystemUiHider(Activity activity, View anchorView, int flags) { + mActivity = activity; + mAnchorView = anchorView; + mFlags = flags; + } + + /** + * Sets up the system UI hider. Should be called from + * {@link Activity#onCreate}. + */ + public abstract void setup(); + + /** + * Returns whether or not the system UI is visible. + */ + public abstract boolean isVisible(); + + /** + * Hide the system UI. + */ + public abstract void hide(); + + /** + * Show the system UI. + */ + public abstract void show(); + + /** + * Toggle the visibility of the system UI. + */ + public void toggle() { + if (isVisible()) { + hide(); + } else { + show(); + } + } + + /** + * Registers a callback, to be triggered when the system UI visibility + * changes. + */ + public void setOnVisibilityChangeListener(OnVisibilityChangeListener listener) { + if (listener == null) { + listener = sDummyListener; + } + + mOnVisibilityChangeListener = listener; + } + + /** + * A dummy no-op callback for use when there is no other listener set. + */ + private static OnVisibilityChangeListener sDummyListener = new OnVisibilityChangeListener() { + @Override + public void onVisibilityChange(boolean visible) { + } + }; + + /** + * A callback interface used to listen for system UI visibility changes. + */ + public interface OnVisibilityChangeListener { + /** + * Called when the system UI visibility has changed. + * + * @param visible True if the system UI is visible. + */ + public void onVisibilityChange(boolean visible); + } +} diff --git a/samples/src/main/java/com/shehabic/droppy_samples/util/SystemUiHiderBase.java b/samples/src/main/java/com/shehabic/droppy_samples/util/SystemUiHiderBase.java new file mode 100644 index 0000000..13d0c4a --- /dev/null +++ b/samples/src/main/java/com/shehabic/droppy_samples/util/SystemUiHiderBase.java @@ -0,0 +1,63 @@ +package com.shehabic.droppy_samples.util; + +import android.app.Activity; +import android.view.View; +import android.view.WindowManager; + +/** + * A base implementation of {@link SystemUiHider}. Uses APIs available in all + * API levels to show and hide the status bar. + */ +public class SystemUiHiderBase extends SystemUiHider { + /** + * Whether or not the system UI is currently visible. This is a cached value + * from calls to {@link #hide()} and {@link #show()}. + */ + private boolean mVisible = true; + + /** + * Constructor not intended to be called by clients. Use + * {@link SystemUiHider#getInstance} to obtain an instance. + */ + protected SystemUiHiderBase(Activity activity, View anchorView, int flags) { + super(activity, anchorView, flags); + } + + @Override + public void setup() { + if ((mFlags & FLAG_LAYOUT_IN_SCREEN_OLDER_DEVICES) == 0) { + mActivity.getWindow().setFlags( + WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, + WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); + } + } + + @Override + public boolean isVisible() { + return mVisible; + } + + @Override + public void hide() { + if ((mFlags & FLAG_FULLSCREEN) != 0) { + mActivity.getWindow().setFlags( + WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + } + mOnVisibilityChangeListener.onVisibilityChange(false); + mVisible = false; + } + + @Override + public void show() { + if ((mFlags & FLAG_FULLSCREEN) != 0) { + mActivity.getWindow().setFlags( + 0, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + } + mOnVisibilityChangeListener.onVisibilityChange(true); + mVisible = true; + } +} diff --git a/samples/src/main/java/com/shehabic/droppy_samples/util/SystemUiHiderHoneycomb.java b/samples/src/main/java/com/shehabic/droppy_samples/util/SystemUiHiderHoneycomb.java new file mode 100644 index 0000000..a37fbf0 --- /dev/null +++ b/samples/src/main/java/com/shehabic/droppy_samples/util/SystemUiHiderHoneycomb.java @@ -0,0 +1,141 @@ +package com.shehabic.droppy_samples.util; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.os.Build; +import android.view.View; +import android.view.WindowManager; + +/** + * An API 11+ implementation of {@link SystemUiHider}. Uses APIs available in + * Honeycomb and later (specifically {@link View#setSystemUiVisibility(int)}) to + * show and hide the system UI. + */ +@TargetApi(Build.VERSION_CODES.HONEYCOMB) +public class SystemUiHiderHoneycomb extends SystemUiHiderBase { + /** + * Flags for {@link View#setSystemUiVisibility(int)} to use when showing the + * system UI. + */ + private int mShowFlags; + + /** + * Flags for {@link View#setSystemUiVisibility(int)} to use when hiding the + * system UI. + */ + private int mHideFlags; + + /** + * Flags to test against the first parameter in + * {@link android.view.View.OnSystemUiVisibilityChangeListener#onSystemUiVisibilityChange(int)} + * to determine the system UI visibility state. + */ + private int mTestFlags; + + /** + * Whether or not the system UI is currently visible. This is cached from + * {@link android.view.View.OnSystemUiVisibilityChangeListener}. + */ + private boolean mVisible = true; + + /** + * Constructor not intended to be called by clients. Use + * {@link SystemUiHider#getInstance} to obtain an instance. + */ + protected SystemUiHiderHoneycomb(Activity activity, View anchorView, int flags) { + super(activity, anchorView, flags); + + mShowFlags = View.SYSTEM_UI_FLAG_VISIBLE; + mHideFlags = View.SYSTEM_UI_FLAG_LOW_PROFILE; + mTestFlags = View.SYSTEM_UI_FLAG_LOW_PROFILE; + + if ((mFlags & FLAG_FULLSCREEN) != 0) { + // If the client requested fullscreen, add flags relevant to hiding + // the status bar. Note that some of these constants are new as of + // API 16 (Jelly Bean). It is safe to use them, as they are inlined + // at compile-time and do nothing on pre-Jelly Bean devices. + mShowFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; + mHideFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_FULLSCREEN; + } + + if ((mFlags & FLAG_HIDE_NAVIGATION) != 0) { + // If the client requested hiding navigation, add relevant flags. + mShowFlags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; + mHideFlags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; + mTestFlags |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; + } + } + + /** + * {@inheritDoc} + */ + @Override + public void setup() { + mAnchorView.setOnSystemUiVisibilityChangeListener(mSystemUiVisibilityChangeListener); + } + + /** + * {@inheritDoc} + */ + @Override + public void hide() { + mAnchorView.setSystemUiVisibility(mHideFlags); + } + + /** + * {@inheritDoc} + */ + @Override + public void show() { + mAnchorView.setSystemUiVisibility(mShowFlags); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isVisible() { + return mVisible; + } + + private View.OnSystemUiVisibilityChangeListener mSystemUiVisibilityChangeListener + = new View.OnSystemUiVisibilityChangeListener() { + @Override + public void onSystemUiVisibilityChange(int vis) { + // Test against mTestFlags to see if the system UI is visible. + if ((vis & mTestFlags) != 0) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { + // Pre-Jelly Bean, we must manually hide the action bar + // and use the old window flags API. + mActivity.getActionBar().hide(); + mActivity.getWindow().setFlags( + WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + } + + // Trigger the registered listener and cache the visibility + // state. + mOnVisibilityChangeListener.onVisibilityChange(false); + mVisible = false; + + } else { + mAnchorView.setSystemUiVisibility(mShowFlags); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { + // Pre-Jelly Bean, we must manually show the action bar + // and use the old window flags API. + mActivity.getActionBar().show(); + mActivity.getWindow().setFlags( + 0, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + } + + // Trigger the registered listener and cache the visibility + // state. + mOnVisibilityChangeListener.onVisibilityChange(true); + mVisible = true; + } + } + }; +} diff --git a/samples/src/main/res/layout/activity_activity_with_fragment.xml b/samples/src/main/res/layout/activity_activity_with_fragment.xml new file mode 100644 index 0000000..9e9d74b --- /dev/null +++ b/samples/src/main/res/layout/activity_activity_with_fragment.xml @@ -0,0 +1,7 @@ + diff --git a/samples/src/main/res/layout/activity_fullscreen.xml b/samples/src/main/res/layout/activity_fullscreen.xml new file mode 100644 index 0000000..9eb1011 --- /dev/null +++ b/samples/src/main/res/layout/activity_fullscreen.xml @@ -0,0 +1,54 @@ + + + + + + + + + + +