We all know we can use a navigation drawer as a new way to navigate in an app (even with a library, like this one) .
We also know that some apps can float above others (as shown on AirCalc, and done like so) ,using a SYSTEM_ALERT_WINDOW permission.
I've noticed that some apps combine expanding & collapsing of views that are on top , like the next ones:
and many more...
We need to merge the 2 concepts of being on top of other apps and allow dragging a handle to show the content on its left side (like a navigation drawer)
Maybe this could show what I mean:
As far as I know, putting anything on top using a system-alert permission requires knowing the size of the view.
However, this is different, since i can't set it to be the entire screen because i don't want to block the rest of the screen in case the user sees only the handle of the navigation drawer.
Is it possible to merge the 2 concepts ?
How would I allow all states to behave nicely while being on top?
for avoiding blocking of touches , I would also like to allow the user to drag the handle up and down, or maybe customize its position in some way.
The navigation drawer is a UI panel that shows your app's main navigation menu. The drawer appears when the user touches the drawer icon in the app bar or when the user swipes a finger from the left edge of the screen.
The user can view the navigation drawer when the user swipes a finger from the left edge of the activity. They can also find it from the home activity by tapping the app icon in the action bar. The drawer icon is displayed on all top-level destinations that use a DrawerLayout.
DrawerLayout acts as a top-level container for window content that allows for interactive "drawer" views to be pulled out from one or both vertical edges of the window.
Based on a few ideas from https://github.com/NikolaDespotoski/DrawerLayoutEdgeToggle I have implemented a much simpler version of a handle for the NavigationDrawer.
Use like this:
View drawer = findViewById(R.id.drawer);
float verticalOffset = 0.2f;
DrawerHandle.attach(drawer, R.layout.handle, verticalOffset);
DrawerHandle:
import android.content.Context;
import android.graphics.Point;
import android.os.Build;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v4.widget.ViewDragHelper;
import android.view.Display;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.FrameLayout;
public class DrawerHandle implements DrawerLayout.DrawerListener {
public static final String TAG = "DrawerHandle";
private ViewGroup mRootView;
private DrawerLayout mDrawerLayout;
private View mHandle;
private View mDrawer;
private float mVerticalOffset;
private int mGravity;
private WindowManager mWM;
private Display mDisplay;
private Point mScreenDimensions = new Point();
private OnClickListener mHandleClickListener = new OnClickListener(){
@Override
public void onClick(View v) {
if(!mDrawerLayout.isDrawerOpen(mGravity)) mDrawerLayout.openDrawer(mGravity);
else mDrawerLayout.closeDrawer(mGravity);
}
};
private OnTouchListener mHandleTouchListener = new OnTouchListener() {
private static final int MAX_CLICK_DURATION = 200;
private long startClickTime;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
startClickTime = System.currentTimeMillis();
break;
}
case MotionEvent.ACTION_UP: {
if(System.currentTimeMillis() - startClickTime < MAX_CLICK_DURATION) {
v.performClick();
return true;
}
}
}
MotionEvent copy = MotionEvent.obtain(event);
copy.setEdgeFlags(ViewDragHelper.EDGE_ALL);
copy.setLocation(event.getRawX() + (mGravity == Gravity.LEFT || mGravity == GravityCompat.START ? -mHandle.getWidth()/2 : mHandle.getWidth() / 2), event.getRawY());
mDrawerLayout.onTouchEvent(copy);
copy.recycle();
return true;
}
};
private int getDrawerViewGravity(View drawerView) {
final int gravity = ((DrawerLayout.LayoutParams) drawerView.getLayoutParams()).gravity;
return GravityCompat.getAbsoluteGravity(gravity, ViewCompat.getLayoutDirection(drawerView));
}
private float getTranslation(float slideOffset){
return (mGravity == GravityCompat.START || mGravity == Gravity.LEFT) ? slideOffset*mDrawer.getWidth() : -slideOffset*mDrawer.getWidth();
}
private void updateScreenDimensions() {
if (Build.VERSION.SDK_INT >= 13) {
mDisplay.getSize(mScreenDimensions);
} else {
mScreenDimensions.x = mDisplay.getWidth();
mScreenDimensions.y = mDisplay.getHeight();
}
}
private DrawerHandle(DrawerLayout drawerLayout, View drawer, int handleLayout, float handleVerticalOffset) {
mDrawer = drawer;
mGravity = getDrawerViewGravity(mDrawer);
mDrawerLayout = drawerLayout;
mRootView = (ViewGroup)mDrawerLayout.getRootView();
LayoutInflater inflater = (LayoutInflater) mDrawerLayout.getContext().getSystemService( Context.LAYOUT_INFLATER_SERVICE );
mHandle = inflater.inflate(handleLayout, mRootView, false);
mWM = (WindowManager) mDrawerLayout.getContext().getSystemService(Context.WINDOW_SERVICE);
mDisplay = mWM.getDefaultDisplay();
mHandle.setOnClickListener(mHandleClickListener);
mHandle.setOnTouchListener(mHandleTouchListener);
mRootView.addView(mHandle, new FrameLayout.LayoutParams(mHandle.getLayoutParams().width, mHandle.getLayoutParams().height, mGravity));
setVerticalOffset(handleVerticalOffset);
mDrawerLayout.setDrawerListener(this);
}
public static DrawerHandle attach(View drawer, int handleLayout, float verticalOffset) {
if (!(drawer.getParent() instanceof DrawerLayout)) throw new IllegalArgumentException("Argument drawer must be direct child of a DrawerLayout");
return new DrawerHandle((DrawerLayout)drawer.getParent(), drawer, handleLayout, verticalOffset);
}
public static DrawerHandle attach(View drawer, int handleLayout) {
return attach(drawer, handleLayout, 0);
}
@Override
public void onDrawerClosed(View arg0) {
}
@Override
public void onDrawerOpened(View arg0) {
}
@Override
public void onDrawerSlide(View arg0, float slideOffset) {
float translationX = getTranslation(slideOffset);
mHandle.setTranslationX(translationX);
}
@Override
public void onDrawerStateChanged(int arg0) {
}
public View getView(){
return mHandle;
}
public View getDrawer() {
return mDrawer;
}
public void setVerticalOffset(float offset) {
updateScreenDimensions();
mVerticalOffset = offset;
mHandle.setY(mVerticalOffset*mScreenDimensions.y);
}
}
Layout:
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<com.fscz.views.BounceViewPager
android:id="@+id/content_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
/>
<com.fscz.views.CirclePageIndicator
android:id="@+id/content_indicator"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:padding="10dp"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:layout_marginTop="100dp"
style="@style/link"
/>
</RelativeLayout>
<LinearLayout
android:id="@+id/drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="right"
android:orientation="vertical"
android:padding="20dp"
android:background="@color/black_transparent"
>
<TextView
android:layout_width="240dp"
android:layout_height="wrap_content"
style="@style/text"
android:text="@string/collections"
android:paddingBottom="20dp"
/>
<ListView
android:id="@+id/drawer_list"
android:layout_width="240dp"
android:layout_height="0dip"
android:choiceMode="singleChoice"
android:divider="@android:color/transparent"
android:dividerHeight="0dp"
android:layout_weight="1"
/>
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
Activity:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_browse);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawer = findViewById(R.id.drawer);
mDrawerList = (ListView) findViewById(R.id.drawer_list);
mDrawerList.setAdapter(new ArrayAdapter<String>(this,
R.layout.drawer_list_item, Preferences.getKnownCollections()));
mDrawerList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapter, View view, int pos, long id) {
Preferences.setActiveCollection(Preferences.getKnownCollections()[pos]);
loader.loadAll(Preferences.getKnownCollections()[pos], BrowseActivity.this);
mDrawerLayout.closeDrawers();
}
});
DrawerHandle.attach(mDrawer, R.layout.handle, 0.2f);
}
Check this library out! Very simple implementation.
https://github.com/kedzie/DraggableDrawers
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With