I have a ViewPager that I want to rotate automatically every 5 seconds, whilst also allowing the user to swipe too. However, when I set the automatic change, the transition animation between pages happens really quickly, and I want this to be slower.
I've seen the answers for this question here:
Slowing speed of Viewpager controller in android
...but they all use reflection. Does anyone know of any way of slowing down the automatic speed of a ViewPager without using reflection?
I thought of using a PageTransformer, but not sure if that would work, and also it would probably affect the speed if the user swiped as well as the automatic one? Unless I can somehow detect the difference, and then do one or another PageTransformation?
Use this Custom View
public class ViewPagerCustomDuration extends ViewPager {
private FixedSpeedScroller mScroller = null;
public ViewPagerCustomDuration(Context context) {
super(context);
init();
}
public ViewPagerCustomDuration(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
/*
* Override the Scroller instance with our own class so we can change the
* duration
*/
private void init() {
try {
Class<?> viewpager = ViewPager.class;
Field scroller = viewpager.getDeclaredField("mScroller");
scroller.setAccessible(true);
mScroller = new FixedSpeedScroller(getContext(),
new DecelerateInterpolator());
scroller.set(this, mScroller);
} catch (Exception ignored) {
}
}
/*
* Set the factor by which the duration will change
*/
public void setScrollDuration(int duration) {
mScroller.setScrollDuration(duration);
}
private class FixedSpeedScroller extends Scroller {
private int mDuration = 500;
public FixedSpeedScroller(Context context) {
super(context);
}
public FixedSpeedScroller(Context context, Interpolator interpolator) {
super(context, interpolator);
}
public FixedSpeedScroller(Context context, Interpolator interpolator, boolean flywheel) {
super(context, interpolator, flywheel);
}
#Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
// Ignore received duration, use fixed one instead
super.startScroll(startX, startY, dx, dy, mDuration);
}
#Override
public void startScroll(int startX, int startY, int dx, int dy) {
// Ignore received duration, use fixed one instead
super.startScroll(startX, startY, dx, dy, mDuration);
}
public void setScrollDuration(int duration) {
mDuration = duration;
}
}
}
You create custom view pager
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.Scroller;
import java.lang.reflect.Field;
public class CustomViewPager extends ViewPager {
private FixedSpeedScroller mScroller = null;
private boolean enabled;
public CustomViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
this.enabled = true;
init();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (this.enabled) {
return super.onTouchEvent(event);
}
init();
return false;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (this.enabled) {
return super.onInterceptTouchEvent(event);
}
return false;
}
public void setPagingEnabled(boolean enabled) {
this.enabled = enabled;
}
/*
* Override the Scroller instance with our own class so we can change the
* duration
*/
private void init() {
try {
Class<?> viewpager = ViewPager.class;
Field scroller = viewpager.getDeclaredField("mScroller");
scroller.setAccessible(true);
mScroller = new FixedSpeedScroller(getContext(),
new DecelerateInterpolator());
scroller.set(this, mScroller);
} catch (Exception ignored) {
}
}
/*
* Set the factor by which the duration will change
*/
public void setScrollDuration(int duration) {
mScroller.setScrollDuration(duration);
}
private class FixedSpeedScroller extends Scroller {
private int mDuration = 500;
public FixedSpeedScroller(Context context) {
super(context);
}
public FixedSpeedScroller(Context context, Interpolator interpolator) {
super(context, interpolator);
}
public FixedSpeedScroller(Context context, Interpolator interpolator, boolean flywheel) {
super(context, interpolator, flywheel);
}
#Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
// Ignore received duration, use fixed one instead
super.startScroll(startX, startY, dx, dy, mDuration);
}
#Override
public void startScroll(int startX, int startY, int dx, int dy) {
// Ignore received duration, use fixed one instead
super.startScroll(startX, startY, dx, dy, mDuration);
}
public void setScrollDuration(int duration) {
mDuration = duration;
}
}
}
you can set duration of view pager according to you
use schedule timer option for auto rotate the pages.
int i = 0;
static Timer timer = new Timer();
//Scroller scroll = new Scroller(this);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_circles);
mAdapter = new TestFragmentAdapter(getSupportFragmentManager());
mPager = (ViewPager) findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
mIndicator = (CirclePageIndicator) findViewById(R.id.indicator);
mIndicator.setViewPager(mPager);
mPager.setCurrentItem(i);
SwitchPage(3);
}
public void SwitchPage(int seconds)
{
if(timer != null)
{
timer.cancel();
}
timer = new Timer(); // At this line a new Thread will be created
timer.schedule(new SwitchPageTask(),
2000, seconds * 2000);
// delay in milliseconds
}
class SwitchPageTask extends TimerTask
{
#Override
public void run() {
runOnUiThread(new Runnable() {
public void run() {
if(i < mAdapter.getCount())
{
i++;
mPager.setCurrentItem(i, true);
}
else
{
i=0;
mPager.setCurrentItem(i, true);
}
}
});
}
}
just cancel the timer like.. timer.cancel().. or
cancel timer from another activity or fragment activity..
textView1_page3.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (SampleCirclesDefault.timer != null) {
SampleCirclesDefault.timer.cancel();
Toast.makeText(getActivity(), "timer
cancled", 1).show();
}
}
});
Related
I have a android.support.v4.view.ViewPager in my application and i have implemented TimerTask to auto scroll the pages and using a custom Scroller to reduce the page transition animation time. I'm trying to stop the auto-scrolling when the user manually scrolls the page.
I followed the #Vikram answer from the below SO question but the programmatic scrolling is detected as user scrolling. And viewPager.OnPageChangeListener is called several times in a single scroll.
Differentiating between user scroll and programatic page change in ViewPager
Is there any way to reduce the transition speed or differentiate user scrolling and programmatic scrolling in this setup?
Here's my custom Scroller class
public class FixedSpeedScroller extends Scroller {
private int mDuration = 1000;
public FixedSpeedScroller(Context context) {
super(context);
}
public FixedSpeedScroller(Context context, Interpolator interpolator) {
super(context, interpolator);
}
public FixedSpeedScroller(Context context, Interpolator interpolator, boolean flywheel) {
super(context, interpolator, flywheel);
}
#Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
// Ignore received duration, use fixed one instead
super.startScroll(startX, startY, dx, dy, mDuration);
}
#Override
public void startScroll(int startX, int startY, int dx, int dy) {
// Ignore received duration, use fixed one instead
super.startScroll(startX, startY, dx, dy, mDuration);
}}
Here's my viewPager setup
public void setUpViewPager() {
mIndicator = (PageIndicatorView) findViewById(R.id.pivGroupFlyer);
mPager = (ViewPager) findViewById(R.id.vpGroupFlyer);
mPager.setAdapter(new GroupFlyerAdapter(this, mFlyerList));
Field mScroller = null;
try {
mScroller = ViewPager.class.getDeclaredField("mScroller");
mScroller.setAccessible(true);
FixedSpeedScroller scroller = new FixedSpeedScroller(mPager.getContext(), new DecelerateInterpolator());
mScroller.set(mPager, scroller);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
mIndicator.setVisibility(View.VISIBLE);
mIndicator.setAnimationType(AnimationType.WORM);
mIndicator.setRadius(2);
mIndicator.setViewPager(mPager);
// Auto start of viewpager
final Handler handler = new Handler();
final Runnable Update = new Runnable() {
public void run() {
if (currentPage == mFlyerList.size()) {
currentPage = 0;
progChange = true;
}
progChange = true;
mPager.setCurrentItem(currentPage++, true);
}
};
final Timer swipeTimer = new Timer();
swipeTimer.schedule(new TimerTask() {
#Override
public void run() {
handler.post(Update);
}
}, 4000, 5000);
if (!(mFlyerList.size() == 0)) {
mGroupHeader.setVisibility(View.INVISIBLE);
}
mPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if(positionOffsetPixels == 0 ){
} else {
if(progChange) {
//programmatically-initiated
Log.e("APP", "SCROLL");
} else {
//user-initiated touch scroll
Log.e("USER", "SCROLL");
swipeTimer.cancel();
}
progChange = false;
}
}
#Override
public void onPageSelected(int position) {
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
}
I have an android application that employs a ViewPager with two pages
When the activity first displays i would like to present each page in turn to the user so that they know they can swipe between to two views.
I have failed to find any docs describing how to do this. I have discovered PageTransformations which sounded promising but the user has to swipe first.
I need my two pages to scroll automatically as soon as the first page in the ViewPager displays.
how can a achieve the desired result?
You can use Timer for this purpose. The following code is self explanatory:
// ---------------------------------------------------------------------------
Timer timer;
int page = 1;
public void pageSwitcher(int seconds) {
timer = new Timer(); // At this line a new Thread will be created
timer.scheduleAtFixedRate(new RemindTask(), 0, seconds * 1000); // delay
// in
// milliseconds
}
// this is an inner class...
class RemindTask extends TimerTask {
#Override
public void run() {
// As the TimerTask run on a seprate thread from UI thread we have
// to call runOnUiThread to do work on UI thread.
runOnUiThread(new Runnable() {
public void run() {
if (page > 4) { // In my case the number of pages are 5
timer.cancel();
// Showing a toast for just testing purpose
Toast.makeText(getApplicationContext(), "Timer stoped",
Toast.LENGTH_LONG).show();
} else {
mViewPager.setCurrentItem(page++);
}
}
});
}
}
// ---------------------------------------------------------------------------
Note 1: Make sure that you call pageSwitcher method after setting up adapter to the viewPager properly inside onCreate method of your activity.
Note 2: The viewPager will swipe every time you launch it. You have to handle it so that it swipes through all pages only once (when the user is viewing the viewPager first time)
Note 3: If you further want to slow the scrolling speed of the viewPager, you can follow this answer on StackOverflow.
Tell me in the comments if that could not help you...
The question is old but I hope it helps someone
My solution using Runnable
Short answer
Runnable runnable = new Runnable() {
public void run() {
if (myAdapter.getCount() == page) {
page = 0;
} else {
page++;
}
viewPager.setCurrentItem(page, true);
handler.postDelayed(this, delay);
}
};
Long answer
Using in an activity
public class activity extends AppCompatActivity {
private Handler handler;
private int delay = 5000; //milliseconds
private ViewPager viewPager;
private int page = 0;
private MyAdapter myAdapter;
Runnable runnable = new Runnable() {
public void run() {
if (myAdapter.getCount() == page) {
page = 0;
} else {
page++;
}
viewPager.setCurrentItem(page, true);
handler.postDelayed(this, delay);
}
};
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handler = new Handler();
viewPager = (ViewPager) findViewById(R.id.viewPager);
myAdapter = new MyAdapter(getSupportFragmentManager());
viewPager.setAdapter(myAdapter);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
page = position;
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
}
#Override
protected void onResume() {
super.onResume();
handler.postDelayed(runnable, delay);
}
#Override
protected void onPause() {
super.onPause();
handler.removeCallbacks(runnable);
}
}
I've created a open source project on github, which implements a auto scroll ViewPager, Example diagram below:
use
<cn.trinea.android.view.autoscrollviewpager.AutoScrollViewPager
android:id="#+id/view_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
replace
<android.support.v4.view.ViewPager
android:id="#+id/view_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
call
startAutoScroll() to start auto scroll.
stopAutoScroll() to stop auto scroll.
More: https://github.com/Trinea/android-auto-scroll-view-pager
Here is autoscroll view pager
package com.otapp.net.view;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.animation.Interpolator;
import android.widget.Scroller;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
public class AutoScrollViewPager extends ViewPager {
public static final int DEFAULT_INTERVAL = 1500;
public static final int LEFT = 0;
public static final int RIGHT = 1;
public static final int SLIDE_BORDER_MODE_NONE = 0;
public static final int SLIDE_BORDER_MODE_CYCLE = 1;
public static final int SLIDE_BORDER_MODE_TO_PARENT = 2;
private long interval = DEFAULT_INTERVAL;
private int direction = RIGHT;
private boolean isCycle = true;
private boolean stopScrollWhenTouch = true;
private int slideBorderMode = SLIDE_BORDER_MODE_NONE;
private boolean isBorderAnimation = true;
private double autoScrollFactor = 1.0;
private double swipeScrollFactor = 1.0;
private Handler handler;
private boolean isAutoScroll = false;
private boolean isStopByTouch = false;
private float touchX = 0f, downX = 0f;
private float touchY = 0f;
private CustomDurationScroller scroller = null;
public static final int SCROLL_WHAT = 0;
public AutoScrollViewPager(Context paramContext) {
super(paramContext);
init();
}
public AutoScrollViewPager(Context paramContext, AttributeSet paramAttributeSet) {
super(paramContext, paramAttributeSet);
init();
}
private void init() {
handler = new MyHandler(this);
setViewPagerScroller();
}
/**
* start auto scroll, first scroll delay time is {#link #getInterval()}
*/
public void startAutoScroll() {
isAutoScroll = true;
sendScrollMessage((long) (interval + scroller.getDuration() / autoScrollFactor * swipeScrollFactor));
}
/**
* start auto scroll
*
* #param delayTimeInMills first scroll delay time
*/
public void startAutoScroll(int delayTimeInMills) {
isAutoScroll = true;
sendScrollMessage(delayTimeInMills);
}
/**
* stop auto scroll
*/
public void stopAutoScroll() {
isAutoScroll = false;
handler.removeMessages(SCROLL_WHAT);
}
/**
* set the factor by which the duration of sliding animation will change while swiping
*/
public void setSwipeScrollDurationFactor(double scrollFactor) {
swipeScrollFactor = scrollFactor;
}
/**
* set the factor by which the duration of sliding animation will change while auto scrolling
*/
public void setAutoScrollDurationFactor(double scrollFactor) {
autoScrollFactor = scrollFactor;
}
private void sendScrollMessage(long delayTimeInMills) {
/** remove messages before, keeps one message is running at most **/
handler.removeMessages(SCROLL_WHAT);
handler.sendEmptyMessageDelayed(SCROLL_WHAT, delayTimeInMills);
}
/**
* set ViewPager scroller to change animation duration when sliding
*/
private void setViewPagerScroller() {
try {
Field scrollerField = ViewPager.class.getDeclaredField("mScroller");
scrollerField.setAccessible(true);
Field interpolatorField = ViewPager.class.getDeclaredField("sInterpolator");
interpolatorField.setAccessible(true);
scroller = new CustomDurationScroller(getContext(), (Interpolator) interpolatorField.get(null));
scrollerField.set(this, scroller);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* scroll only once
*/
public void scrollOnce() {
PagerAdapter adapter = getAdapter();
int currentItem = getCurrentItem();
int totalCount;
if (adapter == null || (totalCount = adapter.getCount()) <= 1) {
return;
}
int nextItem = (direction == LEFT) ? --currentItem : ++currentItem;
if (nextItem < 0) {
if (isCycle) {
setCurrentItem(totalCount - 1, isBorderAnimation);
}
} else if (nextItem == totalCount) {
if (isCycle) {
setCurrentItem(0, isBorderAnimation);
}
} else {
setCurrentItem(nextItem, true);
}
}
/**
* <ul>
* if stopScrollWhenTouch is true
* <li>if event is down, stop auto scroll.</li>
* <li>if event is up, start auto scroll again.</li>
* </ul>
*/
boolean consumeTouch = false;
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int action = MotionEventCompat.getActionMasked(ev);
if (stopScrollWhenTouch) {
if ((action == MotionEvent.ACTION_DOWN) && isAutoScroll) {
isStopByTouch = true;
stopAutoScroll();
} else if (ev.getAction() == MotionEvent.ACTION_UP && isStopByTouch) {
startAutoScroll();
}
}
if (slideBorderMode == SLIDE_BORDER_MODE_TO_PARENT || slideBorderMode == SLIDE_BORDER_MODE_CYCLE) {
touchX = ev.getX();
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
downX = touchX;
touchY = ev.getY();
} else if (action == MotionEvent.ACTION_UP) {
consumeTouch = Math.abs(touchY - ev.getY()) > 0;
}
int currentItem = getCurrentItem();
PagerAdapter adapter = getAdapter();
int pageCount = adapter == null ? 0 : adapter.getCount();
/**
* current index is first one and slide to right or current index is last one and slide to left.<br/>
* if slide border mode is to parent, then requestDisallowInterceptTouchEvent false.<br/>
* else scroll to last one when current item is first one, scroll to first one when current item is last
* one.
*/
if ((currentItem == 0 && downX <= touchX) || (currentItem == pageCount - 1 && downX >= touchX)) {
if (slideBorderMode == SLIDE_BORDER_MODE_TO_PARENT) {
getParent().requestDisallowInterceptTouchEvent(false);
} else {
if (pageCount > 1) {
setCurrentItem(pageCount - currentItem - 1, isBorderAnimation);
}
getParent().requestDisallowInterceptTouchEvent(true);
}
return super.dispatchTouchEvent(ev);
}
}
if (consumeTouch) {
getParent().requestDisallowInterceptTouchEvent(true);
} else {
getParent().requestDisallowInterceptTouchEvent(false);
if (stopScrollWhenTouch)
startAutoScroll();
}
return super.dispatchTouchEvent(ev);
}
private static class MyHandler extends Handler {
private final WeakReference<AutoScrollViewPager> autoScrollViewPager;
public MyHandler(AutoScrollViewPager autoScrollViewPager) {
this.autoScrollViewPager = new WeakReference<AutoScrollViewPager>(autoScrollViewPager);
}
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case SCROLL_WHAT:
AutoScrollViewPager pager = this.autoScrollViewPager.get();
if (pager != null) {
pager.scroller.setScrollDurationFactor(pager.autoScrollFactor);
pager.scrollOnce();
pager.scroller.setScrollDurationFactor(pager.swipeScrollFactor);
pager.sendScrollMessage(pager.interval + pager.scroller.getDuration());
}
default:
break;
}
}
}
public long getInterval() {
return interval;
}
public void setInterval(long interval) {
this.interval = interval;
}
public int getDirection() {
return (direction == LEFT) ? LEFT : RIGHT;
}
public void setDirection(int direction) {
this.direction = direction;
}
public boolean isCycle() {
return isCycle;
}
public void setCycle(boolean isCycle) {
this.isCycle = isCycle;
}
public boolean isStopScrollWhenTouch() {
return stopScrollWhenTouch;
}
public void setStopScrollWhenTouch(boolean stopScrollWhenTouch) {
this.stopScrollWhenTouch = stopScrollWhenTouch;
}
public int getSlideBorderMode() {
return slideBorderMode;
}
public void setSlideBorderMode(int slideBorderMode) {
this.slideBorderMode = slideBorderMode;
}
public boolean isBorderAnimation() {
return isBorderAnimation;
}
public void setBorderAnimation(boolean isBorderAnimation) {
this.isBorderAnimation = isBorderAnimation;
}
public class CustomDurationScroller extends Scroller {
private double scrollFactor = 1;
public CustomDurationScroller(Context context) {
super(context);
}
public CustomDurationScroller(Context context, Interpolator interpolator) {
super(context, interpolator);
}
// #SuppressLint("NewApi")
// public CustomDurationScroller(Context context, Interpolator interpolator, boolean flywheel){
// super(context, interpolator, flywheel);
// }
public void setScrollDurationFactor(double scrollFactor) {
this.scrollFactor = scrollFactor;
}
#Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
super.startScroll(startX, startY, dx, dy, (int) (duration * scrollFactor));
}
}
}
Here is xml implementation
Here is class file implementation
MovieFeaturedAdapter mMovieFeaturedAdapter = new MovieFeaturedAdapter(getActivity(), mCurrentMovies);
vpFeatured.setAdapter(mMovieFeaturedAdapter);
Below method is use to switch pages automatically after some time (you can modify time as per your requirement)
private void timer() {
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
if (currentPage == NUM_PAGES - 1) {
currentPage = 0;
}
view.setCurrentItem(currentPage++, true);
}
});
}
}, 500, 5000);
}
if want to endless scroll in viewpager use infinite scroll viewpager class from below provided link and do minor changes (remove condition) in Runnable interface.
runOnUiThread(new Runnable() {
#Override
public void run() {
view.setCurrentItem(currentPage++, true);
}
});
also,don't forget to cancel timer on Destroy view.
You can use setCurrentItem to change page
If you want to autoplay viewpager pages but above all solution is correct but after autoplay first item consume delay time but it is wrong after autoplay current item switch quickly. I am adding my code below it is working correctly autoplay/pause.
#Override
public void onClick(View v) {
if (!isAutoPlay) {
img_autoplay.setImageResource(R.drawable.pause);
int currentcount = getModel().getCurrentIndex();
currentcount++;
getMainImage().setCurrentItem(currentcount);
autoPlay(getMainImage());
isAutoPlay = true;
} else {
img_autoplay.setImageResource(R.drawable.auto_play);
isAutoPlay = false;
}
}
});
and here is method:
viewPager.postDelayed(new Runnable() {
#Override
public void run() {
try {
if (myAdapter != null
&& viewPager.getAdapter().getCount() > 0
&& isAutoPlay) {
getWindow().addFlags(
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
int currentcount = getModel().getCurrentIndex();
currentcount++;
viewPager.setCurrentItem(currentcount);
if (getModel().isLastCard()) {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
isAutoPlay = false;
packFinished();
getWindow()
.clearFlags(
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
}, 6000);
}
autoPlay(viewPager);
}
} catch (Exception e) {
}
}
}, 6000);
If you are going to switch page automatically then you should disable paging/swiping on ViewPager because if you touch on page and that time page switching then it's not look good means you observed page struck.
To disable paging/swiping on ViewPager,you need to add below code snippet with you custom view pager.
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.animation.Interpolator;
import java.lang.reflect.Field;
public class ViewPagerCustomDuration extends ViewPager {
private boolean swipeable = false;
public ViewPagerCustomDuration(Context context) {
super(context);
postInitViewPager();
}
public ViewPagerCustomDuration(Context context, AttributeSet attrs) {
super(context, attrs);
postInitViewPager();
}
public void setSwipeable(boolean swipeable) {
this.swipeable = swipeable;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (this.swipeable) {
return super.onTouchEvent(event);
}
return false;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (this.swipeable) {
return super.onInterceptTouchEvent(event);
}
return false;
}
private ScrollerCustomDuration mScroller = null;
/**
* Override the Scroller instance with our own class so we can change the
* duration
*/
private void postInitViewPager() {
try {
Field scroller = ViewPager.class.getDeclaredField("mScroller");
scroller.setAccessible(true);
Field interpolator = ViewPager.class.getDeclaredField("sInterpolator");
interpolator.setAccessible(true);
mScroller = new ScrollerCustomDuration(getContext(),
(Interpolator) interpolator.get(null));
scroller.set(this, mScroller);
} catch (Exception e) {
}
}
/**
* Set the factor by which the duration will change
*/
public void setScrollDurationFactor(double scrollFactor) {
mScroller.setScrollDurationFactor(scrollFactor);
}
}
after that,call method from view pager object.
import android.os.Bundle;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;
import java.util.Timer;
import java.util.TimerTask;
public class MainActivity extends AppCompatActivity {
ViewPagerCustomDuration viewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_3);
viewPager = (ViewPagerCustomDuration) findViewById(R.id.viewpager);
viewPager.setScrollDurationFactor(2);
viewPager.setAdapter(new CustomPagerAdapter(this));
viewPager.setSwipeable(false);
pageSwitcher(5);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
}
Timer timer;
int page = 1;
public void pageSwitcher(int seconds) {
timer = new Timer(); // At this line a new Thread will be created
timer.scheduleAtFixedRate(new RemindTask(), 0, seconds * 1000); // delay
// in
// milliseconds
}
// this is an inner class...
class RemindTask extends TimerTask {
#Override
public void run() {
// As the TimerTask run on a seprate thread from UI thread we have
// to call runOnUiThread to do work on UI thread.
runOnUiThread(new Runnable() {
public void run() {
if (page > 4) { // In my case the number of pages are 5
// timer.cancel();
page = 0;
viewPager.setCurrentItem(page++);
// Showing a toast for just testing purpose
Toast.makeText(getApplicationContext(), "Timer stoped",
Toast.LENGTH_LONG).show();
} else {
viewPager.setCurrentItem(page++);
}
}
});
}
}
Scroller class for scroll page smoothly
import android.annotation.SuppressLint;
import android.content.Context;
import android.view.animation.Interpolator;
import android.widget.Scroller;
public class ScrollerCustomDuration extends Scroller {
private double mScrollFactor = 1;
public ScrollerCustomDuration(Context context) {
super(context);
}
public ScrollerCustomDuration(Context context, Interpolator interpolator) {
super(context, interpolator);
}
#SuppressLint("NewApi")
public ScrollerCustomDuration(Context context, Interpolator interpolator, boolean flywheel) {
super(context, interpolator, flywheel);
}
/**
* Set the factor by which the duration will change
*/
public void setScrollDurationFactor(double scrollFactor) {
mScrollFactor = scrollFactor;
}
#Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
super.startScroll(startX, startY, dx, dy, (int) (duration * mScrollFactor));
}
}
For new viewPage2 you can use below code
fun ViewPager2.enableAutoScroll(totalPages: Int): Timer {
val autoTimerTask = Timer()
var currentPageIndex = currentItem
autoTimerTask.schedule(object : TimerTask() {
override fun run() {
currentItem = currentPageIndex++
if (currentPageIndex == totalPages) currentPageIndex = 0
}
}, 0, DELAY_FOUR_SECONDS)
// Stop auto paging when user touch the view
getRecyclerView().setOnTouchListener { _, event ->
if (event.action == MotionEvent.ACTION_DOWN) autoTimerTask.cancel()
false
}
return autoTimerTask // Return the reference for cancel
}
fun ViewPager2.getRecyclerView(): RecyclerView {
val recyclerViewField = ViewPager2::class.java.getDeclaredField("mRecyclerView")
recyclerViewField.isAccessible = true
return recyclerViewField.get(this) as RecyclerView
}
I am developing an android app, where i want to create a slideshow of screens.I am making use of the viewpager for swiping between the screens, and making use of java Timer to automatic slideshow for every 5 seconds.
The problem is, i am not able get a slow and smooth transition from one screen to another. As soon as the 5 seconds is completed ,it immediately moves to the next screen.i need a slow and smooth transition.Is the possible?.Please check out my timer code & view pager code below.
public void slideshowtimer()
{
t.scheduleAtFixedRate(new TimerTask()
{
#Override
public void run()
{
runOnUiThread(new Runnable()
{
public void run()
{
Log.e("inside", "timer - " + viewPagerCurrentItem);
myPager.setCurrentItem(viewPagerCurrentItem++);
}
});
}
}, 0, 5000);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
t = new Timer();
MyPagerAdapter adapter = new MyPagerAdapter();
myPager = (ViewPager) findViewById(R.id.viewPager);
myPager.setAdapter(adapter);
slideshowtimer();
//myPager.setCurrentItem(0);
}
private class MyPagerAdapter extends PagerAdapter {
public int getCount() {
return 3;
}
public Object instantiateItem(View collection, int position) {
LayoutInflater inflater = (LayoutInflater) collection.getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
int resId = 0;
switch (position) {
case 0:
// resId = LayoutOne.newInstance(_context);
resId = R.layout.layout_one;
break;
case 1:
resId = R.layout.layout_two;
break;
case 2:
resId = R.layout.layout_third;
break;
}
View view = inflater.inflate(resId, null);
((ViewPager) collection).addView(view, 0);
return view;
}
Please help.Thanks!
Have you tried setting smooth Scroll to true? Look at the method here.
Have you tried adding your own scroller to the ViewPager. You can set scroll animation to appear using the duration in scroll class.
I did it like this:
viewFlow=(ViewPager)findViewById(R.id.presentationViewPager);
try {
Field mScroller;
Interpolator sInterpolator = new DecelerateInterpolator();
mScroller = ViewPager.class.getDeclaredField("mScroller");
mScroller.setAccessible(true);
FixedSpeedScroller scroller = new FixedSpeedScroller(viewFlow.getContext(), sInterpolator);
// scroller.setFixedDuration(5000);
mScroller.set(viewFlow, scroller);
} catch (NoSuchFieldException e) {
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
}
And here is my Scroller code.:
public class FixedSpeedScroller extends Scroller {
private int mDuration = 600;
public FixedSpeedScroller(Context context) {
super(context);
}
public FixedSpeedScroller(Context context, Interpolator interpolator) {
super(context, interpolator);
}
public FixedSpeedScroller(Context context,Interpolator interpolator, boolean flywheel) {
super(context, interpolator, flywheel);
}
#Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
// Ignore received duration, use fixed one instead
super.startScroll(startX, startY, dx, dy, mDuration);
}
#Override
public void startScroll(int startX, int startY, int dx, int dy) {
// Ignore received duration, use fixed one instead
super.startScroll(startX, startY, dx, dy, mDuration);
}
}
I'm changing slide with the following code:
viewPager.setCurrentItem(index++, true);
But it changes too fast. Is there a way to set manually the animation speed?
I've wanted to do myself and have achieved a solution (using reflection, however). I haven't tested it yet but it should work or need minimal modification. Tested on Galaxy Nexus JB 4.2.1. You need to use a ViewPagerCustomDuration in your XML instead of ViewPager, and then you can do this:
ViewPagerCustomDuration vp = (ViewPagerCustomDuration) findViewById(R.id.myPager);
vp.setScrollDurationFactor(2); // make the animation twice as slow
ViewPagerCustomDuration.java:
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.animation.Interpolator;
import java.lang.reflect.Field;
public class ViewPagerCustomDuration extends ViewPager {
public ViewPagerCustomDuration(Context context) {
super(context);
postInitViewPager();
}
public ViewPagerCustomDuration(Context context, AttributeSet attrs) {
super(context, attrs);
postInitViewPager();
}
private ScrollerCustomDuration mScroller = null;
/**
* Override the Scroller instance with our own class so we can change the
* duration
*/
private void postInitViewPager() {
try {
Field scroller = ViewPager.class.getDeclaredField("mScroller");
scroller.setAccessible(true);
Field interpolator = ViewPager.class.getDeclaredField("sInterpolator");
interpolator.setAccessible(true);
mScroller = new ScrollerCustomDuration(getContext(),
(Interpolator) interpolator.get(null));
scroller.set(this, mScroller);
} catch (Exception e) {
}
}
/**
* Set the factor by which the duration will change
*/
public void setScrollDurationFactor(double scrollFactor) {
mScroller.setScrollDurationFactor(scrollFactor);
}
}
ScrollerCustomDuration.java:
import android.annotation.SuppressLint;
import android.content.Context;
import android.view.animation.Interpolator;
import android.widget.Scroller;
public class ScrollerCustomDuration extends Scroller {
private double mScrollFactor = 1;
public ScrollerCustomDuration(Context context) {
super(context);
}
public ScrollerCustomDuration(Context context, Interpolator interpolator) {
super(context, interpolator);
}
#SuppressLint("NewApi")
public ScrollerCustomDuration(Context context, Interpolator interpolator, boolean flywheel) {
super(context, interpolator, flywheel);
}
/**
* Set the factor by which the duration will change
*/
public void setScrollDurationFactor(double scrollFactor) {
mScrollFactor = scrollFactor;
}
#Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
super.startScroll(startX, startY, dx, dy, (int) (duration * mScrollFactor));
}
}
I have found better solution, based on #df778899's answer and the
Android ValueAnimator API. It works fine without reflection and is very flexible.
Also there is no need for making custom ViewPager and putting it into android.support.v4.view package.
Here is an example:
private void animatePagerTransition(final boolean forward) {
ValueAnimator animator = ValueAnimator.ofInt(0, viewPager.getWidth());
animator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
viewPager.endFakeDrag();
}
#Override
public void onAnimationCancel(Animator animation) {
viewPager.endFakeDrag();
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
animator.setInterpolator(new AccelerateInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
private int oldDragPosition = 0;
#Override
public void onAnimationUpdate(ValueAnimator animation) {
int dragPosition = (Integer) animation.getAnimatedValue();
int dragOffset = dragPosition - oldDragPosition;
oldDragPosition = dragPosition;
viewPager.fakeDragBy(dragOffset * (forward ? -1 : 1));
}
});
animator.setDuration(AppConstants.PAGER_TRANSITION_DURATION_MS);
if (viewPager.beginFakeDrag()) {
animator.start();
}
}
UPDATE:
Just checked if this solution can be used to swipe several pages at once (for example if first page should be showed after the last one). This is slightly modified code to handle specified page count:
private int oldDragPosition = 0;
private void animatePagerTransition(final boolean forward, int pageCount) {
// if previous animation have not finished we can get exception
if (pagerAnimation != null) {
pagerAnimation.cancel();
}
pagerAnimation = getPagerTransitionAnimation(forward, pageCount);
if (viewPager.beginFakeDrag()) { // checking that started drag correctly
pagerAnimation.start();
}
}
private Animator getPagerTransitionAnimation(final boolean forward, int pageCount) {
ValueAnimator animator = ValueAnimator.ofInt(0, viewPager.getWidth() - 1);
animator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
viewPager.endFakeDrag();
}
#Override
public void onAnimationCancel(Animator animation) {
viewPager.endFakeDrag();
}
#Override
public void onAnimationRepeat(Animator animation) {
viewPager.endFakeDrag();
oldDragPosition = 0;
viewPager.beginFakeDrag();
}
});
animator.setInterpolator(new AccelerateInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
int dragPosition = (Integer) animation.getAnimatedValue();
int dragOffset = dragPosition - oldDragPosition;
oldDragPosition = dragPosition;
viewPager.fakeDragBy(dragOffset * (forward ? -1 : 1));
}
});
animator.setDuration(AppConstants.PAGER_TRANSITION_DURATION_MS / pageCount); // remove divider if you want to make each transition have the same speed as single page transition
animator.setRepeatCount(pageCount);
return animator;
}
public class PresentationViewPager extends ViewPager {
public static final int DEFAULT_SCROLL_DURATION = 250;
public static final int PRESENTATION_MODE_SCROLL_DURATION = 1000;
public PresentationViewPager (Context context) {
super(context);
}
public PresentationViewPager (Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setDurationScroll(int millis) {
try {
Class<?> viewpager = ViewPager.class;
Field scroller = viewpager.getDeclaredField("mScroller");
scroller.setAccessible(true);
scroller.set(this, new OwnScroller(getContext(), millis));
} catch (Exception e) {
e.printStackTrace();
}
}
public class OwnScroller extends Scroller {
private int durationScrollMillis = 1;
public OwnScroller(Context context, int durationScroll) {
super(context, new DecelerateInterpolator());
this.durationScrollMillis = durationScroll;
}
#Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
super.startScroll(startX, startY, dx, dy, durationScrollMillis);
}
}
}
Better solution is to simply access the private fields by creating the class in the support package. EDIT This is bound to the MAX_SETTLE_DURATION of 600ms, set by the ViewPagerclass.
package android.support.v4.view;
import android.content.Context;
import android.util.AttributeSet;
public class SlowViewPager extends ViewPager {
// The speed of the scroll used by setCurrentItem()
private static final int VELOCITY = 200;
public SlowViewPager(Context context) {
super(context);
}
public SlowViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) {
setCurrentItemInternal(item, smoothScroll, always, VELOCITY);
}
}
You can, of course, then add a custom attribute so this can be set via XML.
Here is my code used in Librera Reader
public class MyViewPager extends ViewPager {
public MyViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
initMyScroller();
}
private void initMyScroller() {
try {
Class<?> viewpager = ViewPager.class;
Field scroller = viewpager.getDeclaredField("mScroller");
scroller.setAccessible(true);
scroller.set(this, new MyScroller(getContext())); // my liner scroller
Field mFlingDistance = viewpager.getDeclaredField("mFlingDistance");
mFlingDistance.setAccessible(true);
mFlingDistance.set(this, Dips.DP_10);//10 dip
Field mMinimumVelocity = viewpager.getDeclaredField("mMinimumVelocity");
mMinimumVelocity.setAccessible(true);
mMinimumVelocity.set(this, 0); //0 velocity
} catch (Exception e) {
LOG.e(e);
}
}
public class MyScroller extends Scroller {
public MyScroller(Context context) {
super(context, new LinearInterpolator()); // my LinearInterpolator
}
#Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
super.startScroll(startX, startY, dx, dy, 175);//175 duration
}
}
}
I used Cicero Moura's version to make a Kotlin class that still works perfectly as of Android 10.
import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.animation.DecelerateInterpolator
import android.widget.Scroller
import androidx.viewpager.widget.ViewPager
class CustomViewPager(context: Context, attrs: AttributeSet) :
ViewPager(context, attrs) {
private companion object {
const val DEFAULT_SPEED = 1000
}
init {
setScrollerSpeed(DEFAULT_SPEED)
}
var scrollDuration = DEFAULT_SPEED
set(millis) {
setScrollerSpeed(millis)
}
private fun setScrollerSpeed(millis: Int) {
try {
ViewPager::class.java.getDeclaredField("mScroller")
.apply {
isAccessible = true
set(this#CustomViewPager, OwnScroller(millis))
}
} catch (e: Exception) {
e.printStackTrace()
}
}
inner class OwnScroller(private val durationScrollMillis: Int) : Scroller(context, AccelerateDecelerateInterpolator()) {
override fun startScroll(startX: Int, startY: Int, dx: Int, dy: Int, duration: Int) {
super.startScroll(startX, startY, dx, dy, durationScrollMillis)
}
}
}
Initializing from the activity class:
viewPager.apply {
scrollDuration = 2000
adapter = pagerAdapter
}
After wasting my whole day I found a solution set offscreenPageLimit to total no. of the page.
In order to keep a constant length ViewPager scrolls smooth, setOffScreenLimit(page.length) will keep all the views in memory. However, this poses a problem for any animations that involves calling View.requestLayout function (e.g. any animation that involves making changes to the margin or bounds). It makes them really slow (as per Romain Guy) because the all of the views that's in memory will be invalidated as well. So I tried a few different ways to make things smooth but overriding requestLayout and other invalidate methods will cause many other problems.
A good compromise is to dynamically modify the off screen limit so that most of the scrolls between pages will be very smooth while making sure that all of the in page animations smooth by removing the views when the user. This works really well when you only have 1 or 2 views that will have to make other views off memory.
***Use this when no any solution works because by setting offeset limit u will load all the fragments at the same time
I'm creating an Android app that searches for items based on the visible area of the MapView. Is there a way to set up a listener on my MapView to detect when a map has been panned or zoomed?
try mapview-overlay-manager, it is a extension for overlayer for android maps,
it has some simplified OnGestureListener, few example:
onSingleTap(MotionEvent, ManagedOverlay, GeoPoint, OverlayItem)
onDoubleTap(MotionEvent, ManagedOverlay, GeoPoint, OverlayItem)
onLongPress(MotionEvent, ManagedOverlay, GeoPoint, OverlayItem)
onZoom(ZoomEvent, ManagedOverlay)
onScrolled(...)
link:http://code.google.com/p/mapview-overlay-manager/ hope it helps
You can create a SimpleMapView that extends MapView.
public class SimpleMapView extends MapView {
private int currentZoomLevel = -1;
private GeoPoint currentCenter;
private List<ZoomChangeListener> zoomEvents = new ArrayList<ZoomChangeListener>();
private List<PanChangeListener> panEvents = new ArrayList<PanChangeListener>();
public SimpleMapView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public SimpleMapView(Context context, String apiKey) {
super(context, apiKey);
}
public SimpleMapView(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
*
* #return
*/
public int[][] getBounds() {
GeoPoint center = getMapCenter();
int latitudeSpan = getLatitudeSpan();
int longtitudeSpan = getLongitudeSpan();
int[][] bounds = new int[2][2];
bounds[0][0] = center.getLatitudeE6() - (latitudeSpan / 2);
bounds[0][1] = center.getLongitudeE6() - (longtitudeSpan / 2);
bounds[1][0] = center.getLatitudeE6() + (latitudeSpan / 2);
bounds[1][1] = center.getLongitudeE6() + (longtitudeSpan / 2);
return bounds;
}
public boolean onTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_UP) {
GeoPoint centerGeoPoint = this.getMapCenter();
if (currentCenter == null ||
(currentCenter.getLatitudeE6() != centerGeoPoint.getLatitudeE6()) ||
(currentCenter.getLongitudeE6() != centerGeoPoint.getLongitudeE6()) ) {
firePanEvent(currentCenter, this.getMapCenter());
}
currentCenter = this.getMapCenter();
}
return super.onTouchEvent(ev);
}
#Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if(getZoomLevel() != currentZoomLevel){
fireZoomLevel(currentZoomLevel, getZoomLevel());
currentZoomLevel = getZoomLevel();
}
}
#Override
public void setSatellite(boolean on){
super.setSatellite(on);
}
#Override
public MapController getController(){
return super.getController();
}
private void fireZoomLevel(int old, int current){
for(ZoomChangeListener event : zoomEvents){
event.onZoom(old, current);
}
}
private void firePanEvent(GeoPoint old, GeoPoint current){
for(PanChangeListener event : panEvents){
event.onPan(old, current);
}
}
public void addZoomChangeListener(ZoomChangeListener listener){
this.zoomEvents.add(listener);
}
public void addPanChangeListener(PanChangeListener listener){
this.panEvents.add(listener);
}
}
You have the Listeners you can put the code for pan or zoom.
Then in your xml:
<com.androidnatic.maps.SimpleMapView android:clickable="true"
android:layout_height="match_parent" android:id="#+id/mapView"
android:layout_width="match_parent"
android:apiKey="xxx">
</com.androidnatic.maps.SimpleMapView>
And then in your code you can specify the Pan Listener:
mapView.addPanChangeListener(new PanChangeListener() {
#Override
public void onPan(GeoPoint old, GeoPoint current) {
//TODO
}
});
Sadly, there is no built-in functionality to do this in the MapView tools (a strange oversight since this functionality is in the JavaScript SDK, as well as the iOS SDK).
You can deal with this easily enough though by using a Runnable and just polling the MapView. I do this by keeping track of the "last" state of:
getLatitudeSpan();
getLongitudeSpan();
getCenter();
getZoomLevel();
And then comparing them to the current values. If the values of changed, you know the map view has moved. If not, you can do nothing.
Either way, reschedule the runnable for another run after 500ms or so and repeat the process. You can use onResume() and onPause() to remove the callback for the Runnable and restart it as necessary.
The MapView class can track changes using the onLayout method.
i.e.
class CustomMapView extends MapView {
protected void onLayout(boolean changed,int left, int right, int top, int bottom){
super.onLayout(changed,left, right, top, bottom);
if(changed){
// do something special
}
}
}
The only way that I can think of is to extends the MapView and override the OnTouchEvent and watch for the Up action. This will tell you that the user has finished moving and you can get the lat/lon span to determine the region you should check out.
Old question, but I wrote a class a while back called ExMapView which fires an event when the map region starts changing (onRegionBeginChange) and when it stops changing (onRegionEndChange). This class is for use with the old MapView, not V2.0. Hope it helps someone.
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
public class ExMapView extends MapView {
private static final String TAG = ExMapView.class.getSimpleName();
private static final int DURATION_DEFAULT = 700;
private OnRegionChangedListener onRegionChangedListener;
private GeoPoint previousMapCenter;
private int previousZoomLevel;
private int changeDuration; // This is the duration between when the user stops moving the map around and when the onRegionEndChange event fires.
private boolean isTouched = false;
private boolean regionChanging = false;
private Runnable onRegionEndChangeTask = new Runnable() {
public void run() {
regionChanging = false;
previousMapCenter = getMapCenter();
previousZoomLevel = getZoomLevel();
if (onRegionChangedListener != null) {
onRegionChangedListener.onRegionEndChange(ExMapView.this, previousMapCenter, previousZoomLevel);
}
}
};
public ExMapView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ExMapView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public ExMapView(Context context, String apiKey) {
super(context, apiKey);
init();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
isTouched = event.getAction() != MotionEvent.ACTION_UP;
return super.onTouchEvent(event);
}
#Override
public void computeScroll() {
super.computeScroll();
// If the map region is still changing (user is still scrolling or zooming), reset timer for onRegionEndChange.
if ((!isTouched && !getMapCenter().equals(previousMapCenter)) || (previousZoomLevel != getZoomLevel())) {
// If the region has just begun changing, fire off onRegionBeginChange event.
if (!regionChanging) {
regionChanging = true;
if (onRegionChangedListener != null) {
onRegionChangedListener.onRegionBeginChange(this, previousMapCenter, previousZoomLevel);
}
}
// Reset timer for onRegionEndChange.
removeCallbacks(onRegionEndChangeTask);
postDelayed(onRegionEndChangeTask, changeDuration);
}
}
private void init() {
changeDuration = DURATION_DEFAULT;
previousMapCenter = getMapCenter();
previousZoomLevel = getZoomLevel();
}
public void setOnRegionChangedListener(OnRegionChangedListener listener) {
onRegionChangedListener = listener;
}
public void setChangeDuration(int duration) {
changeDuration = duration;
}
public interface OnRegionChangedListener {
public abstract void onRegionBeginChange(ExMapView exMapView, GeoPoint geoPoint, int zoomLevel);
public abstract void onRegionEndChange(ExMapView exMapView, GeoPoint geoPoint, int zoomLevel);
}
}