custom touch listener for views in ViewPager

This commit is contained in:
Peter Siegmund
2016-05-03 17:39:06 +02:00
parent 5fec760399
commit b9c44a28fc
5 changed files with 258 additions and 158 deletions
@@ -1,106 +1,110 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="@+id/race_content_header"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/sap_gray">
android:layout_height="match_parent">
<TextView
android:id="@+id/timer_text"
<com.sap.sailing.racecommittee.app.ui.layouts.TimePanelHeaderLayout
android:id="@+id/race_content_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/side_padding"
android:layout_marginRight="@dimen/side_padding"
android:layout_marginTop="@dimen/header_margin_top"
android:gravity="center"
android:singleLine="true"
android:textColor="?attr/white"
android:textSize="@dimen/panel_button_header_size"
tools:text="@string/time"/>
android:layout_height="match_parent"
android:background="?attr/sap_gray">
<ImageView
android:id="@+id/time_marker"
android:layout_width="match_parent"
android:layout_height="@dimen/thin_line"
android:layout_alignParentBottom="true"
android:src="?attr/marker"/>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/time_marker"
android:layout_centerHorizontal="true"
android:layout_marginBottom="@dimen/side_padding"
android:baselineAligned="false">
<RelativeLayout
android:id="@+id/start_time_container"
android:layout_width="wrap_content"
<TextView
android:id="@+id/timer_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true">
<TextView
android:id="@+id/time_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="@+id/linked_locked_area"
android:textColor="?attr/white"
android:textSize="@dimen/panel_button_caption_size"
tools:text="@string/time_start"/>
<LinearLayout
android:id="@+id/linked_locked_area"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginRight="6dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/time_start_lock"
android:layout_width="@dimen/side_button_lockSize"
android:layout_height="@dimen/side_button_lockSize"
android:src="?attr/lock_outline"
android:visibility="gone"
tools:visibility="visible"/>
<ImageView
android:id="@+id/linked_race"
android:layout_width="@dimen/side_button_lockSize"
android:layout_height="@dimen/side_button_lockSize"
android:layout_gravity="center_vertical"
android:src="?attr/link_24dp"
android:visibility="gone"
tools:visibility="visible"/>
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/side_padding"
android:layout_toRightOf="@+id/start_time_container">
android:layout_marginRight="@dimen/side_padding"
android:layout_marginTop="@dimen/header_margin_top"
android:gravity="center"
android:singleLine="true"
android:textColor="?attr/white"
android:textSize="@dimen/panel_button_header_size"
tools:text="@string/time"/>
<TextView
android:id="@+id/current_time"
<ImageView
android:id="@+id/time_marker"
android:layout_width="match_parent"
android:layout_height="@dimen/thin_line"
android:layout_alignParentBottom="true"
android:src="?attr/marker"/>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/time_marker"
android:layout_centerHorizontal="true"
android:layout_marginBottom="@dimen/side_padding"
android:baselineAligned="false">
<RelativeLayout
android:id="@+id/start_time_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_centerVertical="true"
android:drawableLeft="?attr/access_time_18dp"
android:drawablePadding="6dp"
android:gravity="center"
android:textColor="?attr/white"
android:textSize="@dimen/panel_button_caption_size"
android:visibility="invisible"
tools:text="@string/time"
tools:visibility="visible"/>
</RelativeLayout>
android:layout_centerVertical="true">
</RelativeLayout>
<TextView
android:id="@+id/time_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="@+id/linked_locked_area"
android:textColor="?attr/white"
android:textSize="@dimen/panel_button_caption_size"
tools:text="@string/time_start"/>
<LinearLayout
android:id="@+id/linked_locked_area"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginRight="6dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/time_start_lock"
android:layout_width="@dimen/side_button_lockSize"
android:layout_height="@dimen/side_button_lockSize"
android:src="?attr/lock_outline"
android:visibility="gone"
tools:visibility="visible"/>
<ImageView
android:id="@+id/linked_race"
android:layout_width="@dimen/side_button_lockSize"
android:layout_height="@dimen/side_button_lockSize"
android:layout_gravity="center_vertical"
android:src="?attr/link_24dp"
android:visibility="gone"
tools:visibility="visible"/>
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/side_padding"
android:layout_toRightOf="@+id/start_time_container">
<TextView
android:id="@+id/current_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_centerVertical="true"
android:drawableLeft="?attr/access_time_18dp"
android:drawablePadding="6dp"
android:gravity="center"
android:textColor="?attr/white"
android:textSize="@dimen/panel_button_caption_size"
android:visibility="invisible"
tools:text="@string/time"
tools:visibility="visible"/>
</RelativeLayout>
</RelativeLayout>
</com.sap.sailing.racecommittee.app.ui.layouts.TimePanelHeaderLayout>
</RelativeLayout>
@@ -28,6 +28,7 @@ import com.sap.sailing.racecommittee.app.R;
import com.sap.sailing.racecommittee.app.data.DataManager;
import com.sap.sailing.racecommittee.app.domain.ManagedRace;
import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.StartTimeFragment;
import com.sap.sailing.racecommittee.app.ui.layouts.TimePanelHeaderLayout;
import com.sap.sailing.racecommittee.app.utils.RaceHelper;
import com.sap.sailing.racecommittee.app.utils.TickSingleton;
import com.sap.sailing.racecommittee.app.utils.TimeUtils;
@@ -43,7 +44,7 @@ public class TimePanelFragment extends BasePanelFragment {
private IntentReceiver mReceiver;
private SimpleDateFormat dateFormat;
private View mRaceHeader;
private TimePanelHeaderLayout mRaceHeader;
private View mTimeLock;
private TextView mCurrentTime;
private TextView mHeaderTime;
@@ -69,9 +70,12 @@ public class TimePanelFragment extends BasePanelFragment {
mStateListener = new RaceStateChangedListener();
mRaceHeader = ViewHelper.get(layout, R.id.race_content_header);
if (mRaceHeader != null) {
mRaceHeader.setOnClickListener(new RaceHeaderClick());
}
mRaceHeader.setRunnable(new Runnable() {
@Override
public void run() {
new RaceHeaderClick().onClick(null);
}
});
mTimeLock = ViewHelper.get(layout, R.id.time_start_lock);
mCurrentTime = ViewHelper.get(layout, R.id.current_time);
@@ -0,0 +1,42 @@
package com.sap.sailing.racecommittee.app.ui.layouts;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.RelativeLayout;
import com.sap.sailing.racecommittee.app.ui.utils.TouchEventListener;
public class TimePanelHeaderLayout extends RelativeLayout {
private TouchEventListener mTouchEventListener;
public TimePanelHeaderLayout(Context context) {
this(context, null);
}
public TimePanelHeaderLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TimePanelHeaderLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mTouchEventListener = new TouchEventListener(this);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mTouchEventListener != null) {
return mTouchEventListener.onTouchEvent(event);
} else {
return super.onTouchEvent(event);
}
}
public void setRunnable(Runnable clickRunnable) {
if (mTouchEventListener != null) {
mTouchEventListener.setClickRunnable(clickRunnable);
}
}
}
@@ -0,0 +1,83 @@
package com.sap.sailing.racecommittee.app.ui.utils;
import java.lang.ref.WeakReference;
import android.support.v4.view.ViewConfigurationCompat;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
public class TouchEventListener {
private WeakReference<View> mView;
private Runnable mClickRunnable;
private float mStartX;
private float mStartY;
private boolean mInXRange;
private boolean mInYRange;
private int mTouchSlop;
private boolean mEnabled;
public TouchEventListener(View view) {
mView = new WeakReference<>(view);
final ViewConfiguration configuration = ViewConfiguration.get(view.getContext());
mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
mEnabled = true;
}
public boolean onTouchEvent(MotionEvent event) {
int action = event.getActionMasked();
View view = mView.get();
if (view == null) {
return false;
}
switch (action) {
case MotionEvent.ACTION_DOWN:
mInXRange = true;
mInYRange = true;
view.getParent().requestDisallowInterceptTouchEvent(true);
mStartX = event.getX();
mStartY = event.getY();
return true;
case MotionEvent.ACTION_MOVE:
boolean inLimit = false;
if (mInXRange) {
inLimit = Math.abs(event.getX() - mStartX) <= mTouchSlop;
mInXRange = inLimit;
} else {
view.getParent().requestDisallowInterceptTouchEvent(false);
}
if (mInYRange) {
mInYRange = Math.abs(event.getY() - mStartY) <= mTouchSlop;
}
return inLimit;
case MotionEvent.ACTION_UP:
view.getParent().requestDisallowInterceptTouchEvent(false);
if (mInXRange && mEnabled) {
if (mClickRunnable != null) {
mClickRunnable.run();
return true;
}
}
break;
default:
break;
}
return false;
}
public void setClickRunnable(Runnable runnable) {
mClickRunnable = runnable;
}
public void setEnabled(boolean enabled) {
mEnabled = enabled;
}
}
@@ -6,18 +6,17 @@ import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.support.annotation.StringRes;
import android.support.v4.view.ViewConfigurationCompat;
import android.support.v7.app.AlertDialog;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.Switch;
import android.widget.TextView;
import com.sap.sailing.racecommittee.app.R;
import com.sap.sailing.racecommittee.app.ui.utils.TouchEventListener;
import com.sap.sailing.racecommittee.app.utils.ThemeHelper;
public class PanelButton extends FrameLayout implements DialogInterface.OnClickListener {
@@ -40,13 +39,8 @@ public class PanelButton extends FrameLayout implements DialogInterface.OnClickL
private int mType;
private Runnable mClickRunnable;
private float mStartX;
private boolean mUseThis;
private int mTouchSlop;
private boolean mClickEnabled;
private PanelButtonClick mListener;
private TouchEventListener mTouchEventListener;
public PanelButton(Context context) {
this(context, null);
@@ -61,6 +55,31 @@ public class PanelButton extends FrameLayout implements DialogInterface.OnClickL
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PanelButton);
Runnable clickRunnable = new Runnable() {
@Override
public void run() {
if (mLock != null && mLock.getVisibility() == VISIBLE && isNormal()) {
if (mType == 2 && mSwitch != null) {
mSwitch.setChecked(!mSwitch.isChecked());
}
showChangeDialog(PanelButton.this);
} else {
if (mType == 2) {
if (mListener != null && mSwitch != null) {
mListener.onChangedSwitch(PanelButton.this, mSwitch.isChecked());
}
} else {
if (mListener != null) {
mListener.onClick(PanelButton.this);
}
}
}
}
};
mTouchEventListener = new TouchEventListener(this);
mTouchEventListener.setClickRunnable(clickRunnable);
setPanelType(a.getInt(R.styleable.PanelButton_buttonType, 0));
switch (mType) {
@@ -93,31 +112,6 @@ public class PanelButton extends FrameLayout implements DialogInterface.OnClickL
a.recycle();
setMarkerLevel(LEVEL_NORMAL);
mClickRunnable = new Runnable() {
@Override
public void run() {
if (mLock != null && mLock.getVisibility() == VISIBLE && isNormal()) {
if (mType == 2 && mSwitch != null) {
mSwitch.setChecked(!mSwitch.isChecked());
}
showChangeDialog(PanelButton.this);
} else {
if (mType == 2) {
if (mListener != null && mSwitch != null) {
mListener.onChangedSwitch(PanelButton.this, mSwitch.isChecked());
}
} else {
if (mListener != null) {
mListener.onClick(PanelButton.this);
}
}
}
}
};
final ViewConfiguration configuration = ViewConfiguration.get(context);
mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
}
public void setListener(PanelButtonClick listener) {
@@ -150,11 +144,11 @@ public class PanelButton extends FrameLayout implements DialogInterface.OnClickL
mType = type;
switch (type) {
case 2:
mClickEnabled = false;
mTouchEventListener.setEnabled(false);
break;
default:
mClickEnabled = true;
mTouchEventListener.setEnabled(true);
}
}
@@ -346,34 +340,7 @@ public class PanelButton extends FrameLayout implements DialogInterface.OnClickL
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_DOWN:
mUseThis = true;
getParent().requestDisallowInterceptTouchEvent(true);
mStartX = event.getX();
return true;
case MotionEvent.ACTION_MOVE:
boolean inLimit = false;
if (mUseThis) {
inLimit = Math.abs(event.getX() - mStartX) <= mTouchSlop;
mUseThis = inLimit;
} else {
getParent().requestDisallowInterceptTouchEvent(false);
}
return inLimit;
case MotionEvent.ACTION_UP:
getParent().requestDisallowInterceptTouchEvent(false);
if (mUseThis && mClickEnabled) {
performClick();
mClickRunnable.run();
return true;
}
}
return false;
return mTouchEventListener.onTouchEvent(event);
}
public interface PanelButtonClick {