Context menu states in progress
This commit is contained in:
parent
90ce687568
commit
2547b4b020
4 changed files with 198 additions and 42 deletions
|
@ -8,7 +8,7 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@android:color/transparent">
|
android:background="@android:color/transparent">
|
||||||
|
|
||||||
<LinearLayout
|
<net.osmand.plus.mapcontextmenu.InterceptorLinearLayout
|
||||||
android:id="@+id/context_menu_main"
|
android:id="@+id/context_menu_main"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
@ -19,7 +19,6 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?attr/bg_map_context_menu"
|
android:background="?attr/bg_map_context_menu"
|
||||||
android:clickable="true"
|
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
@ -398,7 +397,6 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:background="?selectableItemBackground"
|
android:background="?selectableItemBackground"
|
||||||
android:clickable="true"
|
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingBottom="@dimen/context_menu_main_actions_padding_bottom"
|
android:paddingBottom="@dimen/context_menu_main_actions_padding_bottom"
|
||||||
|
@ -581,7 +579,7 @@
|
||||||
android:foreground="@drawable/bg_contextmenu_shadow"
|
android:foreground="@drawable/bg_contextmenu_shadow"
|
||||||
android:foregroundGravity="top|fill_horizontal">
|
android:foregroundGravity="top|fill_horizontal">
|
||||||
|
|
||||||
<ScrollView
|
<net.osmand.plus.LockableScrollView
|
||||||
android:id="@+id/context_menu_bottom_scroll"
|
android:id="@+id/context_menu_bottom_scroll"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
@ -596,10 +594,11 @@
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</ScrollView>
|
</net.osmand.plus.LockableScrollView>
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</net.osmand.plus.mapcontextmenu.InterceptorLinearLayout>
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/context_menu_fab_container"
|
android:id="@+id/context_menu_fab_container"
|
||||||
|
|
56
OsmAnd/src/net/osmand/plus/LockableScrollView.java
Normal file
56
OsmAnd/src/net/osmand/plus/LockableScrollView.java
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
package net.osmand.plus;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.widget.ScrollView;
|
||||||
|
|
||||||
|
public class LockableScrollView extends ScrollView {
|
||||||
|
|
||||||
|
// true if we can scroll (not locked)
|
||||||
|
// false if we cannot scroll (locked)
|
||||||
|
private boolean mScrollable = true;
|
||||||
|
|
||||||
|
public LockableScrollView(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LockableScrollView(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScrollingEnabled(boolean enabled) {
|
||||||
|
mScrollable = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isScrollable() {
|
||||||
|
return mScrollable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTouchEvent(MotionEvent ev) {
|
||||||
|
switch (ev.getAction()) {
|
||||||
|
case MotionEvent.ACTION_DOWN:
|
||||||
|
// if we can scroll pass the event to the superclass
|
||||||
|
if (mScrollable) {
|
||||||
|
return super.onTouchEvent(ev);
|
||||||
|
}
|
||||||
|
// only continue to handle the touch event if scrolling enabled
|
||||||
|
return mScrollable;
|
||||||
|
default:
|
||||||
|
return super.onTouchEvent(ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||||
|
// Don't do anything with intercepted touch events if
|
||||||
|
// we are not scrollable
|
||||||
|
if (!mScrollable) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return super.onInterceptTouchEvent(ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
package net.osmand.plus.mapcontextmenu;
|
||||||
|
|
||||||
|
import android.annotation.TargetApi;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.ViewConfiguration;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
|
public class InterceptorLinearLayout extends LinearLayout {
|
||||||
|
private int mTouchSlop;
|
||||||
|
private boolean mIsScrolling;
|
||||||
|
private float mDownY;
|
||||||
|
private OnTouchListener listener;
|
||||||
|
|
||||||
|
public InterceptorLinearLayout(Context context) {
|
||||||
|
this(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InterceptorLinearLayout(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
ViewConfiguration vc = ViewConfiguration.get(context);
|
||||||
|
mTouchSlop = vc.getScaledTouchSlop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public InterceptorLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||||
|
super(context, attrs, defStyleAttr);
|
||||||
|
ViewConfiguration vc = ViewConfiguration.get(context);
|
||||||
|
mTouchSlop = vc.getScaledTouchSlop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
public InterceptorLinearLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||||
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
|
ViewConfiguration vc = ViewConfiguration.get(context);
|
||||||
|
mTouchSlop = vc.getScaledTouchSlop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTouchSlop() {
|
||||||
|
return mTouchSlop;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isScrolling() {
|
||||||
|
return mIsScrolling;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setListener(OnTouchListener listener) {
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||||
|
boolean handled = false;
|
||||||
|
final int action = ev.getAction();
|
||||||
|
|
||||||
|
if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
|
||||||
|
mIsScrolling = false;
|
||||||
|
handled = false;
|
||||||
|
} else {
|
||||||
|
switch (action) {
|
||||||
|
case MotionEvent.ACTION_DOWN:
|
||||||
|
mIsScrolling = false;
|
||||||
|
mDownY = ev.getRawY();
|
||||||
|
handled = false;
|
||||||
|
case MotionEvent.ACTION_MOVE:
|
||||||
|
if (mIsScrolling) {
|
||||||
|
handled = true;
|
||||||
|
} else {
|
||||||
|
final int yDiff = calculateDistanceY(ev);
|
||||||
|
if (Math.abs(yDiff) > mTouchSlop) {
|
||||||
|
mIsScrolling = true;
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listener != null) {
|
||||||
|
listener.onTouch(this, ev);
|
||||||
|
}
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int calculateDistanceY(MotionEvent ev) {
|
||||||
|
return (int) (ev.getRawY() - mDownY);
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,6 +37,7 @@ import net.osmand.data.LatLon;
|
||||||
import net.osmand.data.PointDescription;
|
import net.osmand.data.PointDescription;
|
||||||
import net.osmand.data.QuadPoint;
|
import net.osmand.data.QuadPoint;
|
||||||
import net.osmand.data.RotatedTileBox;
|
import net.osmand.data.RotatedTileBox;
|
||||||
|
import net.osmand.plus.LockableScrollView;
|
||||||
import net.osmand.plus.OsmandApplication;
|
import net.osmand.plus.OsmandApplication;
|
||||||
import net.osmand.plus.OsmandSettings;
|
import net.osmand.plus.OsmandSettings;
|
||||||
import net.osmand.plus.R;
|
import net.osmand.plus.R;
|
||||||
|
@ -71,8 +72,10 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
|
||||||
public static final float SKIP_HALF_SCREEN_STATE_KOEF = .21f;
|
public static final float SKIP_HALF_SCREEN_STATE_KOEF = .21f;
|
||||||
public static final int ZOOM_IN_STANDARD = 17;
|
public static final int ZOOM_IN_STANDARD = 17;
|
||||||
|
|
||||||
|
public static final int CURRENT_Y_UNDEFINED = Integer.MAX_VALUE;
|
||||||
|
|
||||||
private View view;
|
private View view;
|
||||||
private View mainView;
|
private InterceptorLinearLayout mainView;
|
||||||
private View zoomButtonsView;
|
private View zoomButtonsView;
|
||||||
private ImageButton zoomInButtonView;
|
private ImageButton zoomInButtonView;
|
||||||
private ImageButton zoomOutButtonView;
|
private ImageButton zoomOutButtonView;
|
||||||
|
@ -246,6 +249,7 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
|
||||||
final View.OnTouchListener slideTouchListener = new View.OnTouchListener() {
|
final View.OnTouchListener slideTouchListener = new View.OnTouchListener() {
|
||||||
private float dy;
|
private float dy;
|
||||||
private float dyMain;
|
private float dyMain;
|
||||||
|
private float mDownY;
|
||||||
private VelocityTracker velocity;
|
private VelocityTracker velocity;
|
||||||
private boolean slidingUp;
|
private boolean slidingUp;
|
||||||
private boolean slidingDown;
|
private boolean slidingDown;
|
||||||
|
@ -257,6 +261,7 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
|
||||||
@Override
|
@Override
|
||||||
public boolean onTouch(View v, MotionEvent event) {
|
public boolean onTouch(View v, MotionEvent event) {
|
||||||
|
|
||||||
|
if (event.getY() <= menuTopViewHeight) {
|
||||||
if (singleTapDetector.onTouchEvent(event)) {
|
if (singleTapDetector.onTouchEvent(event)) {
|
||||||
moving = false;
|
moving = false;
|
||||||
if (hasMoved) {
|
if (hasMoved) {
|
||||||
|
@ -272,20 +277,24 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (event.getAction()) {
|
switch (event.getAction()) {
|
||||||
case MotionEvent.ACTION_DOWN:
|
case MotionEvent.ACTION_DOWN:
|
||||||
hasMoved = false;
|
hasMoved = false;
|
||||||
|
mDownY = event.getRawY();
|
||||||
dy = event.getY();
|
dy = event.getY();
|
||||||
dyMain = getViewY();
|
dyMain = getViewY();
|
||||||
velocity = VelocityTracker.obtain();
|
velocity = VelocityTracker.obtain();
|
||||||
velocityY = 0;
|
velocityY = 0;
|
||||||
maxVelocityY = 0;
|
maxVelocityY = 0;
|
||||||
velocity.addMovement(event);
|
velocity.addMovement(event);
|
||||||
moving = true;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MotionEvent.ACTION_MOVE:
|
case MotionEvent.ACTION_MOVE:
|
||||||
|
if (Math.abs(event.getRawY() - mDownY) > mainView.getTouchSlop()) {
|
||||||
|
moving = true;
|
||||||
|
}
|
||||||
if (moving) {
|
if (moving) {
|
||||||
hasMoved = true;
|
hasMoved = true;
|
||||||
float y = event.getY();
|
float y = event.getY();
|
||||||
|
@ -328,20 +337,12 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
View topView = view.findViewById(R.id.context_menu_top_view);
|
|
||||||
topView.setOnTouchListener(slideTouchListener);
|
|
||||||
View topShadowAllView = view.findViewById(R.id.context_menu_top_shadow_all);
|
View topShadowAllView = view.findViewById(R.id.context_menu_top_shadow_all);
|
||||||
AndroidUtils.setBackground(getMapActivity(), topShadowAllView, nightMode, R.drawable.bg_map_context_menu_light,
|
AndroidUtils.setBackground(getMapActivity(), topShadowAllView, nightMode, R.drawable.bg_map_context_menu_light,
|
||||||
R.drawable.bg_map_context_menu_dark);
|
R.drawable.bg_map_context_menu_dark);
|
||||||
topShadowAllView.setOnTouchListener(new View.OnTouchListener() {
|
|
||||||
@Override
|
((InterceptorLinearLayout) mainView).setListener(slideTouchListener);
|
||||||
public boolean onTouch(View v, MotionEvent event) {
|
mainView.setOnTouchListener(slideTouchListener);
|
||||||
if (event.getY() <= dpToPx(SHADOW_HEIGHT_TOP_DP) || event.getAction() != MotionEvent.ACTION_DOWN)
|
|
||||||
return slideTouchListener.onTouch(v, event);
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
buildHeader();
|
buildHeader();
|
||||||
|
|
||||||
|
@ -507,7 +508,9 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
|
||||||
|
|
||||||
buildBottomView();
|
buildBottomView();
|
||||||
|
|
||||||
view.findViewById(R.id.context_menu_bottom_scroll).setBackgroundColor(getResources()
|
LockableScrollView bottomScrollView = (LockableScrollView) view.findViewById(R.id.context_menu_bottom_scroll);
|
||||||
|
bottomScrollView.setScrollingEnabled(false);
|
||||||
|
bottomScrollView.setBackgroundColor(getResources()
|
||||||
.getColor(nightMode ? R.color.ctx_menu_bottom_view_bg_dark : R.color.ctx_menu_bottom_view_bg_light));
|
.getColor(nightMode ? R.color.ctx_menu_bottom_view_bg_dark : R.color.ctx_menu_bottom_view_bg_light));
|
||||||
view.findViewById(R.id.context_menu_bottom_view).setBackgroundColor(getResources()
|
view.findViewById(R.id.context_menu_bottom_view).setBackgroundColor(getResources()
|
||||||
.getColor(nightMode ? R.color.ctx_menu_bottom_view_bg_dark : R.color.ctx_menu_bottom_view_bg_light));
|
.getColor(nightMode ? R.color.ctx_menu_bottom_view_bg_dark : R.color.ctx_menu_bottom_view_bg_light));
|
||||||
|
@ -659,7 +662,7 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
|
||||||
|
|
||||||
private void applyPosY(final int currentY, final boolean needCloseMenu, boolean needMapAdjust,
|
private void applyPosY(final int currentY, final boolean needCloseMenu, boolean needMapAdjust,
|
||||||
final int previousMenuState, final int newMenuState, int dZoom) {
|
final int previousMenuState, final int newMenuState, int dZoom) {
|
||||||
final int posY = getPosY(needCloseMenu);
|
final int posY = getPosY(currentY, needCloseMenu);
|
||||||
if (currentY != posY || dZoom != 0) {
|
if (currentY != posY || dZoom != 0) {
|
||||||
if (posY < currentY) {
|
if (posY < currentY) {
|
||||||
updateMainViewLayout(posY);
|
updateMainViewLayout(posY);
|
||||||
|
@ -897,12 +900,6 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
View bottomView = view.findViewById(R.id.context_menu_bottom_view);
|
View bottomView = view.findViewById(R.id.context_menu_bottom_view);
|
||||||
if (menu.isExtended()) {
|
if (menu.isExtended()) {
|
||||||
bottomView.setOnTouchListener(new View.OnTouchListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onTouch(View v, MotionEvent event) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
menu.build(bottomView);
|
menu.build(bottomView);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1244,10 +1241,10 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getPosY() {
|
private int getPosY() {
|
||||||
return getPosY(false);
|
return getPosY(CURRENT_Y_UNDEFINED, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getPosY(boolean needCloseMenu) {
|
private int getPosY(final int currentY, boolean needCloseMenu) {
|
||||||
if (needCloseMenu) {
|
if (needCloseMenu) {
|
||||||
return screenHeight;
|
return screenHeight;
|
||||||
}
|
}
|
||||||
|
@ -1272,8 +1269,23 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
|
||||||
posY = Math.max(posY, minHalfY);
|
posY = Math.max(posY, minHalfY);
|
||||||
break;
|
break;
|
||||||
case MenuState.FULL_SCREEN:
|
case MenuState.FULL_SCREEN:
|
||||||
|
if (currentY != CURRENT_Y_UNDEFINED) {
|
||||||
|
int maxPosY = viewHeight - menuFullHeightMax;
|
||||||
|
int minPosY = Math.max(maxPosY, minHalfY);
|
||||||
|
if (maxPosY > minPosY) {
|
||||||
|
maxPosY = minPosY;
|
||||||
|
}
|
||||||
|
if (currentY > minPosY) {
|
||||||
|
posY = minPosY;
|
||||||
|
} else if (currentY < maxPosY) {
|
||||||
|
posY = maxPosY;
|
||||||
|
} else {
|
||||||
|
posY = currentY;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
posY = -dpToPx(SHADOW_HEIGHT_TOP_DP);
|
posY = -dpToPx(SHADOW_HEIGHT_TOP_DP);
|
||||||
posY = addStatusBarHeightIfNeeded(posY);
|
posY = addStatusBarHeightIfNeeded(posY);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in a new issue