Skip to content
This repository has been archived by the owner on Jul 22, 2024. It is now read-only.

Commit

Permalink
Fixes #2524 Honeycomb button clipping (#2601)
Browse files Browse the repository at this point in the history
* Honeycomb button clipping

* Forward event if not inside
  • Loading branch information
keianhzo authored and MortimerGoro committed Jan 10, 2020
1 parent 91e3eaa commit 237441f
Show file tree
Hide file tree
Showing 5 changed files with 424 additions and 27 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package org.mozilla.vrbrowser.ui.views;

import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Region;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;

import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;

import org.mozilla.vrbrowser.utils.ViewUtils;

import java.util.Deque;

public class ClippedEventDelegate implements View.OnHoverListener, View.OnTouchListener {

private View mView;
private Region mRegion;
private boolean mHovered;
private boolean mTouched;
private OnClickListener mClickListener;

public ClippedEventDelegate(@DrawableRes int res, @NonNull View view) {
mView = view;
mHovered = false;
mTouched = false;

view.getViewTreeObserver().addOnGlobalLayoutListener(
() -> {
Path path = createPathFromResource(res);
RectF bounds = new RectF();
path.computeBounds(bounds, true);

bounds = new RectF();
path.computeBounds(bounds, true);
mRegion = new Region();
mRegion.setPath(path, new Region((int) bounds.left, (int) bounds.top, (int) bounds.right, (int) bounds.bottom));
});
}

public void setOnClickListener(OnClickListener listener) {
mClickListener = listener;
}

private Path createPathFromResource(@DrawableRes int res) {
VectorShape shape = new VectorShape(mView.getContext(), res);
shape.onResize(mView.getWidth(), mView.getHeight());
Deque<VectorShape.Layer> layers = shape.getLayers();
VectorShape.Layer layer = layers.getFirst();

// TODO Handle state changes and update the Region based on the new current state shape

return layer.transformedPath;
}

@Override
public boolean onHover(View v, MotionEvent event) {
if(!mRegion.contains((int)event.getX(),(int) event.getY())) {
if (mHovered) {
mHovered = false;
event.setAction(MotionEvent.ACTION_HOVER_EXIT);
return v.onHoverEvent(event);
}

return true;

} else {
if (!mHovered) {
mHovered = true;
event.setAction(MotionEvent.ACTION_HOVER_ENTER);
}

return v.onHoverEvent(event);
}
}

@Override
public boolean onTouch(View v, MotionEvent event) {
v.getParent().requestDisallowInterceptTouchEvent(true);

if(!mRegion.contains((int)event.getX(),(int) event.getY())) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
if (mTouched) {
v.requestFocus();
v.requestFocusFromTouch();
if (mClickListener != null) {
mClickListener.onClick(v);
}
}
v.setPressed(false);
mTouched = false;
}

return true;

} else {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
v.setPressed(true);
mTouched = true;
return true;

case MotionEvent.ACTION_UP:
if (mTouched && ViewUtils.isInsideView(v, (int)event.getRawX(), (int)event.getRawY())) {
v.requestFocus();
v.requestFocusFromTouch();
if (mClickListener != null) {
mClickListener.onClick(v);
}
}
v.setPressed(false);
mTouched = false;
return true;

case MotionEvent.ACTION_MOVE:
return true;

case MotionEvent.ACTION_CANCEL:
v.setPressed(false);
mTouched = false;
return true;
}

return false;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import org.mozilla.vrbrowser.R;
import org.mozilla.vrbrowser.utils.DeviceType;
import org.mozilla.vrbrowser.utils.SystemUtils;
import org.mozilla.vrbrowser.utils.ViewUtils;

public class HoneycombButton extends LinearLayout {

Expand All @@ -33,6 +32,7 @@ public class HoneycombButton extends LinearLayout {
private String mSecondaryButtonText;
private Drawable mButtonIcon;
private boolean mButtonIconHover;
private VectorClippedEventDelegate mEventDelegate;

public HoneycombButton(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, R.style.honeycombButtonTheme);
Expand Down Expand Up @@ -109,41 +109,53 @@ private void initialize(Context aContext) {
mSecondaryText.setClickable(false);
}

setOnHoverListener((view, motionEvent) -> false);
mEventDelegate = new VectorClippedEventDelegate(R.drawable.settings_honeycomb_background, this);
setOnHoverListener(mEventDelegate);
setOnTouchListener(mEventDelegate);
}


@Override
public void setOnClickListener(@Nullable OnClickListener aListener) {
ViewUtils.setStickyClickListener(this, aListener);
mEventDelegate.setOnClickListener(aListener);
}

@Override
public void setOnHoverListener(final OnHoverListener l) {
super.setOnHoverListener((view, motionEvent) -> {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_HOVER_ENTER:
if (mIcon != null && mText != null) {
if (mButtonIconHover) {
mIcon.setColorFilter(new PorterDuffColorFilter(getResources().getColor(R.color.asphalt, getContext().getTheme()), PorterDuff.Mode.MULTIPLY));
}
mText.setTextColor(getContext().getColor(R.color.asphalt));
mSecondaryText.setTextColor(getContext().getColor(R.color.asphalt));
public boolean onHoverEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_HOVER_ENTER:
if (mIcon != null && mText != null) {
if (mButtonIconHover) {
mIcon.setColorFilter(new PorterDuffColorFilter(getResources().getColor(R.color.asphalt, getContext().getTheme()), PorterDuff.Mode.MULTIPLY));
}
break;
case MotionEvent.ACTION_HOVER_EXIT:
if (mIcon != null && mText != null) {
if (mButtonIconHover) {
mIcon.setColorFilter(new PorterDuffColorFilter(getResources().getColor(R.color.fog, getContext().getTheme()), PorterDuff.Mode.MULTIPLY));
}
mText.setTextColor(getContext().getColor(R.color.fog));
mSecondaryText.setTextColor(getContext().getColor(R.color.fog));
mText.setTextColor(getContext().getColor(R.color.asphalt));
mSecondaryText.setTextColor(getContext().getColor(R.color.asphalt));
}
break;
case MotionEvent.ACTION_HOVER_EXIT:
if (mIcon != null && mText != null) {
if (mButtonIconHover) {
mIcon.setColorFilter(new PorterDuffColorFilter(getResources().getColor(R.color.fog, getContext().getTheme()), PorterDuff.Mode.MULTIPLY));
}
break;
}
mText.setTextColor(getContext().getColor(R.color.fog));
mSecondaryText.setTextColor(getContext().getColor(R.color.fog));
}
break;
}

return l.onHover(view, motionEvent);
});
if (mEventDelegate.isInside(event)) {
return super.onHoverEvent(event);

} else {
setHovered(false);
if (mIcon != null && mText != null) {
if (mButtonIconHover) {
mIcon.setColorFilter(new PorterDuffColorFilter(getResources().getColor(R.color.fog, getContext().getTheme()), PorterDuff.Mode.MULTIPLY));
}
mText.setTextColor(getContext().getColor(R.color.fog));
mSecondaryText.setTextColor(getContext().getColor(R.color.fog));
}
return false;
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package org.mozilla.vrbrowser.ui.views;

import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Region;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewTreeObserver;

import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;

import org.mozilla.vrbrowser.utils.ViewUtils;

import java.util.Deque;

public class VectorClippedEventDelegate implements View.OnHoverListener, View.OnTouchListener {

private View mView;
private @DrawableRes int mRes;
private Region mRegion;
private boolean mHovered;
private boolean mTouched;
private OnClickListener mClickListener;

VectorClippedEventDelegate(@DrawableRes int res, @NonNull View view) {
mView = view;
mRes = res;
mHovered = false;
mTouched = false;

view.getViewTreeObserver().addOnGlobalLayoutListener(mLayoutListener);
}

private ViewTreeObserver.OnGlobalLayoutListener mLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Path path = createPathFromResource(mRes);
RectF bounds = new RectF();
path.computeBounds(bounds, true);

bounds = new RectF();
path.computeBounds(bounds, true);
mRegion = new Region();
mRegion.setPath(path, new Region((int) bounds.left, (int) bounds.top, (int) bounds.right, (int) bounds.bottom));

mView.getViewTreeObserver().removeOnGlobalLayoutListener(mLayoutListener);
}
};

public void setOnClickListener(OnClickListener listener) {
mClickListener = listener;
}

private Path createPathFromResource(@DrawableRes int res) {
VectorShape shape = new VectorShape(mView.getContext(), res);
shape.onResize(mView.getWidth(), mView.getHeight());
Deque<VectorShape.Layer> layers = shape.getLayers();
VectorShape.Layer layer = layers.getFirst();

// TODO Handle state changes and update the Region based on the new current state shape

return layer.transformedPath;
}

@Override
public boolean onHover(View v, MotionEvent event) {
if(!isInside(event)) {
if (mHovered) {
mHovered = false;
event.setAction(MotionEvent.ACTION_HOVER_EXIT);
return v.onHoverEvent(event);
}

return false;

} else {
if (!mHovered) {
mHovered = true;
event.setAction(MotionEvent.ACTION_HOVER_ENTER);
}

return v.onHoverEvent(event);
}
}

@Override
public boolean onTouch(View v, MotionEvent event) {
v.getParent().requestDisallowInterceptTouchEvent(true);

if(!isInside(event)) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
if (mTouched) {
v.requestFocus();
v.requestFocusFromTouch();
if (mClickListener != null) {
mClickListener.onClick(v);
}
}
v.setPressed(false);
mTouched = false;
}

return true;

} else {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
v.setPressed(true);
mTouched = true;
return true;

case MotionEvent.ACTION_UP:
if (mTouched && ViewUtils.isInsideView(v, (int)event.getRawX(), (int)event.getRawY())) {
v.requestFocus();
v.requestFocusFromTouch();
if (mClickListener != null) {
mClickListener.onClick(v);
}
}
v.setPressed(false);
mTouched = false;
return true;

case MotionEvent.ACTION_MOVE:
return true;

case MotionEvent.ACTION_CANCEL:
v.setPressed(false);
mTouched = false;
return true;
}

return false;
}
}

public boolean isInside(MotionEvent event) {
return mRegion.contains((int)event.getX(),(int) event.getY());
}

}
Loading

0 comments on commit 237441f

Please sign in to comment.