Skip to content

Instantly share code, notes, and snippets.

@adneal
Last active May 19, 2018 13:05
Show Gist options
  • Save adneal/7287925 to your computer and use it in GitHub Desktop.
Save adneal/7287925 to your computer and use it in GitHub Desktop.
A way to swipe between the children of a ViewPager using the ActionBar. Similar the Google Chrome app for Android.
<com.your_package_name.ProgressTracker xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:enabled="false"
android:orientation="horizontal"
android:paddingEnd="8dp" >
<ImageView
android:id="@+id/up"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:contentDescription="@null"
android:visibility="gone" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:orientation="vertical" >
<TextView
android:id="@+id/action_bar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:text="@string/app_name"
android:textIsSelectable="false"
android:textSize="18sp" />
<TextView
android:id="@+id/action_bar_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="-3dp"
android:ellipsize="end"
android:singleLine="true"
android:textIsSelectable="false"
android:textSize="14sp"
android:visibility="gone" />
</LinearLayout>
</com.your_package_name.ProgressTracker>
/**
* A {@link LinearLayout} that tracks a user's finger movement
*
* @author Andrew Neal (andrew@seeingpixels.org)
*/
public class ProgressTracker extends LinearLayout {
/** The callback invoked depicting the current finger movement */
private OnProgressChangeListner mCallback;
/** Used to track the velocity of the finger movement */
private VelocityTracker mVelocityTracker;
/** The current progress */
private float mProgress;
/**
* Constructor for <code>ProgressTracker</code>
*
* @param context The {@link Context} to use
* @param attrs The attributes of the XML tag that is inflating the view
*/
public ProgressTracker(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* {@inheritDoc}
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
final int index = event.getActionIndex();
final int pointerId = event.getPointerId(index);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// Initialize the VelocityTracker
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
} else {
mVelocityTracker.clear();
}
// Track the movement
mVelocityTracker.addMovement(event);
// Invoke the callback
if (mCallback != null) {
mCallback.onStartTrackingTouch();
}
break;
case MotionEvent.ACTION_MOVE:
// Track the movement and capture the velocity
mVelocityTracker.addMovement(event);
mVelocityTracker.computeCurrentVelocity(1000);
// Calculate the progress and invoke the callback
if (mCallback != null) {
mProgress = mVelocityTracker.getXVelocity(pointerId);
mCallback.onProgressChanged((int) mProgress);
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
// Clean up
mVelocityTracker.clear();
mProgress = 0;
// Invoke the callback
if (mCallback != null) {
mCallback.onStopTrackingTouch();
}
break;
default:
break;
}
return true;
}
/**
* {@inheritDoc}
*/
@Override
protected void onDetachedFromWindow() {
// Release any resources
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
mCallback = null;
super.onDetachedFromWindow();
}
/**
* Initializes the progress callback
*
* @param callback The {@link OnProgressChangeListner} to use
*/
public void setOnProgressChangeListner(OnProgressChangeListner callback) {
mCallback = callback;
}
/**
* An interface for monitoring the progress of the user's finger across the
* <code>ProgressTracker</code> {@link View}
*/
public interface OnProgressChangeListner {
/**
* Indicates that {@link MotionEvent#ACTION_MOVE} has been called and
* therefore the attached {@link ViewPager} should call
* {@link ViewPager#fakeDragBy(float)}
*
* @param progress The current progress
*/
void onProgressChanged(int progress);
/**
* Indicates that {@link MotionEvent#ACTION_DOWN} has been called and
* therefore the attached {@link ViewPager} should call
* {@link ViewPager#beginFakeDrag()}
*/
void onStartTrackingTouch();
/**
* Indicates that {@link MotionEvent#ACTION_UP} or
* {@link MotionEvent#ACTION_CANCEL} has been called and therefore the
* attached {@link ViewPager} should call
* {@link ViewPager#endFakeDrag()}
*/
void onStopTrackingTouch();
}
}
// Inflate the custom ActionBar layout
final LayoutInflater inflater = LayoutInflater.from(this);
final View progress = inflater.inflate(R.layout.action_bar, null);
((ProgressTracker) progress).setOnProgressChangeListner(new OnProgressChangeListner() {
@Override
public void onProgressChanged(int progress) {
if (pager.isFakeDragging()) {
pager.fakeDragBy(progress / 100);
}
}
@Override
public void onStartTrackingTouch() {
if (!pager.isFakeDragging()) {
pager.beginFakeDrag();
}
}
@Override
public void onStopTrackingTouch() {
if (pager.isFakeDragging()) {
pager.endFakeDrag();
}
}
});
// Apply the custom view the ActionBar
final ActionBar actionBar = getActionBar();
actionBar.setDisplayShowCustomEnabled(true);
actionBar.setDisplayShowTitleEnabled(false);
final LayoutParams params = new LayoutParams(
android.view.ViewGroup.LayoutParams.MATCH_PARENT,
android.view.ViewGroup.LayoutParams.MATCH_PARENT);
actionBar.setCustomView(progress, params);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment