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);
}
}
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 need to create the following layout to my viewpager:
I'm using PageContainer:
public class PagerContainer extends FrameLayout implements ViewPager.OnPageChangeListener{
private ViewPager mPager;
boolean mNeedsRedraw = false;
public PagerContainer(Context context)
{
super(context);
init();
}
public PagerContainer(Context context, AttributeSet attrs)
{
super(context, attrs);
init();
}
public PagerContainer(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
init();
}
private void init()
{
// Disable clipping of children so non-selected pages are visible
setClipChildren(false);
// Child clipping doesn't work with hardware acceleration in Android
// 3.x/4.x
// You need to set this value here if using hardware acceleration in an
// application targeted at these releases.
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
#Override
protected void onFinishInflate()
{
try
{
mPager = (ViewPager) getChildAt(0);
mPager.setOnPageChangeListener(this);
} catch (Exception e)
{
throw new IllegalStateException("The root child of PagerContainer must be a ViewPager");
}
}
public ViewPager getViewPager()
{
return mPager;
}
private Point mCenter = new Point();
private Point mInitialTouch = new Point();
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
mCenter.x = w / 2;
mCenter.y = h / 2;
}
#Override
public boolean onTouchEvent(MotionEvent ev)
{
// We capture any touches not already handled by the ViewPager
// to implement scrolling from a touch outside the pager bounds.
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mInitialTouch.x = (int) ev.getX();
mInitialTouch.y = (int) ev.getY();
default:
ev.offsetLocation(mCenter.x - mInitialTouch.x, mCenter.y - mInitialTouch.y);
break;
}
return mPager.dispatchTouchEvent(ev);
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
{
// Force the container to redraw on scrolling.
// Without this the outer pages render initially and then stay static
if (mNeedsRedraw)
invalidate();
}
#Override
public void onPageSelected(int position)
{}
#Override
public void onPageScrollStateChanged(int state)
{
mNeedsRedraw = (state != ViewPager.SCROLL_STATE_IDLE);
}
`
And seting like this:
PagerContainer mContainer = (PagerContainer) mainView.findViewById(R.id.pagerContainer);
pager = mContainer.getViewPager();
pager.setOffscreenPageLimit(pagerAdapter.getCount());
pager.setPageMargin(getPx(20));
pager.setClipChildren(false);
But the side pages has the same size of the active page.
I've tried to use pager.setPageMargin but only sets margim between pages.
Can someone help me?
you need a PageTransfomer for that the changes the scale of the page on the left and on the right of the central one. When you implement the interface you'll be forced to implement the
public void transformPage (View page, float position) {
}
page is the current ViewPager's page, while float position is the position of page relative to the current center position of the pager. What you probably want is to change the scaleX and scaleY of page, when position is grater then 1 or less then -1. E.g.
public void transformPage (View page, float position) {
if (position > 1 || position < -1) {
ViewCompat.scaleX(page, 0.75f * paget.getWidth());
ViewCompat.scaleY(page, 0.75f * paget.getHeight());
} else if (position == 0) {
ViewCompat.scaleX(page, 1f);
ViewCompat.scaleY(page, 1f);
}
}
I have not the possibility to try it out so, please check for typo/cast.
I am using ViewPager with FragmentStatePageAdapter to show a number of views where user can go through. With current implementation only one page is changed at any single swipe. Instead I want to flip through multiple views based on user swipe. If swipe is long/fast i need to flip through multiple views and vice versa.
here is my current code
public class MyAdapter extends FragmentStatePagerAdapter
{
public MyAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
#Override
public int getCount() {
return 10;
}
#Override
public Fragment getItem(int position) {
return ItemFragment.init(position);
}
}
PageContainer class
public class PagerContainer extends FrameLayout implements ViewPager.OnPageChangeListener {
private ViewPager mPager;
boolean mNeedsRedraw = false;
public PagerContainer(Context context) {
super(context);
init();
}
public PagerContainer(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public PagerContainer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
//Disable clipping of children so non-selected pages are visible
setClipChildren(false);
//Child clipping doesn't work with hardware acceleration in Android 3.x/4.x
//You need to set this value here if using hardware acceleration in an
// application targeted at these releases.
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
#Override
protected void onFinishInflate() {
try {
mPager = (ViewPager) getChildAt(0);
mPager.setOnPageChangeListener(this);
} catch (Exception e) {
throw new IllegalStateException("The root child of PagerContainer must be a ViewPager");
}
}
public ViewPager getViewPager() {
return mPager;
}
private Point mCenter = new Point();
private Point mInitialTouch = new Point();
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mCenter.x = w / 2;
mCenter.y = h / 2;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
//We capture any touches not already handled by the ViewPager
// to implement scrolling from a touch outside the pager bounds.
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mInitialTouch.x = (int)ev.getX();
mInitialTouch.y = (int)ev.getY();
default:
ev.offsetLocation(mCenter.x - mInitialTouch.x, mCenter.y - mInitialTouch.y);
break;
}
return mPager.dispatchTouchEvent(ev);
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
//Force the container to redraw on scrolling.
//Without this the outer pages render initially and then stay static
if (mNeedsRedraw) invalidate();
}
#Override
public void onPageSelected(int position) { }
#Override
public void onPageScrollStateChanged(int state) {
mNeedsRedraw = (state != ViewPager.SCROLL_STATE_IDLE);
}
}
How can I do this in android?
Thanks
You can change the view by calling:
ViewPager.setCurrentItem(int index)
ViewPager.setCurrentItem(int index, bool animation)
You must handle the sliding commands yourself, but on a certain slide you cloud call setCurrentItem of the ViewPager. The setCurrentItem method also allows you to enable or disable animations.
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();
}
}
});
Can a View Pager be made to auto slide or autopage. I have my viewpager set up to use the adapter like the below and it works fine:-
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.gridslide);
ImagePagerAdapter mAdapter = new ImagePagerAdapter(
getSupportFragmentManager(),4);
ViewPager mPager = (ViewPager) findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
}
And the adapter is like below:-
public static class ImagePagerAdapter extends FragmentStatePagerAdapter {
private final int mSize;
public ImagePagerAdapter(FragmentManager fm, int size) {
super(fm);
mSize = size;
}
#Override
public int getCount() {
return mSize;
}
#Override
public Fragment getItem(int position) {
Log.v(TAG,"position="+position);
return TheFragment.newInstance(position);
}}
However I would want to know how to make these fragments autoslide in a viewpager.
Setting smoothScroll = true in setCurrentItem(int item, boolean smoothScroll) does not always have the smooth scroll effect. Suppose if you have less than 5 pages in you viewpager, you will hardly notice the smooth scroll.
In this scenario, the hard way to do it is to put it in a for loop
//This will scroll page-by-page so that you can view scroll happening
for (int i = 0; i < mAdapter.getCount()-1; i++)
mPager.setCurrentItem(i, true);
If some one needs more slower scroll, they can use postDelayed() like this...
static int i=0;
private final Handler handler = new Handler();
somefunction()
{
handle.post(ViewPagerVisibleScroll);
}
Runnable ViewPagerVisibleScroll= new Runnable() {
#Override
public void run() {
if(i <= mAdapter.getCount()-1)
{
mPager.setCurrentItem(i, true);
handle.postDelayed(TopChartAnimation, 100);
i++;
}
}
};
Sleep is always NOT recommended : If some one needs more slower scroll, they may use a sleep in this for loop...
#Override
public void onClick(View v) {
Runnable runnable = new Runnable() {
#Override
public void run() {
for (int i = 0; i < mAdapter.getCount()-1; i++) {
final int value = i;
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(new Runnable() {
#Override
public void run() {
mPager.setCurrentItem(value, true);
}
});
}
}
};
new Thread(runnable).start();
}
Probably, You should take a look at the following APIs ViewPager.beginFakeDrag(), ViewPager. fakeDragBy(float offset) and ViewPager.endFakeDrag() if You want drag simulation. Also, setCurrentItem() APIs provide ability to set current page and do it smoothly.
Simplest way I could suggest to make slide automatically is to setup Handler with simple Runnable which would call pager methods for setting item in the activity and just do postDelayed() for it. And don't forget to call removeCallbacks() for it when user interaction or e.g. activity pause.
First Create Slider class extend with TimerTask
public class SliderTimer extends TimerTask {
private ViewPager viewPager;
private int size;
private Activity activity;
public SliderTimer(ViewPager viewPager, int size, Activity activity) {
this.viewPager = viewPager;
this.size = size;
this.activity = activity;
}
#Override
public void run() {
activity.runOnUiThread(() -> {
if (viewPager.getCurrentItem() < size - 1) {
viewPager.setCurrentItem(viewPager.getCurrentItem() + 1, true);
} else {
viewPager.setCurrentItem(0, true);
}
});
}
}
Next Create SpeedSlowScroller for slow scrolling
public class SpeedSlowScroller extends Scroller {
private int mDuration = 2500;
public SpeedSlowScroller(Context context) {
super(context);
}
public SpeedSlowScroller(Context context, Interpolator interpolator) {
super(context, interpolator);
}
public SpeedSlowScroller(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);
}
}
Finally add SpeedSlowScroller into ViewPager, and SliderTimer for auto scroll
try {
Field mScroller = ViewPager.class.getDeclaredField("mScroller");
mScroller.setAccessible(true);
SpeedSlowScroller scroller = new SpeedSlowScroller(_context);
mScroller.set(your_viewpager, scroller);
Timer timer = new Timer();
timer.scheduleAtFixedRate(new SliderTimer(your_viewpager, models.size(), activity), 4000, 6000);
} catch (Exception ignored) {
}
short answer 2020
After you set your viewPager adapter
private Runnable runnable = null;
public void function DisplaySlider(){
sliderItemAdapter = new SliderItemAdapter(getActivity(), mSliderList);//push the data to the adapter
mViewPager.setAdapter(sliderItemAdapter); //set the adapter to the view pager
startAutoSlider(sliderItem.getCount());
}
private void startAutoSlider(final int count) {
runnable = new Runnable() {
#Override
public void run() {
int pos = mViewPager.getCurrentItem();
pos = pos + 1;
if (pos >= count) pos = 0;
mViewPager.setCurrentItem(pos);
handler.postDelayed(runnable, 3000);
}
};
handler.postDelayed(runnable, 3000);
}
And finally don`t forget to free the memory from the callbacks
#Override
public void onDestroy() {
if (runnable != null) handler.removeCallbacks(runnable);
super.onDestroy();
}