Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Launch an animation onstart CustomViewPager

I succeed to create an animation at the start of my CustomViewPager which act like a Carousel. So here, my items came from the left and goes to the right in 3 seconds. The thing is it's just a translation I was wondering if it's possible to just make my viewpager scroll from far away to his final position.

Do you see a way to do this ? Regards.

Edit : So I try something else and I have created my custom ScrollToAnimation. I succeed to create what I want but the movement is not smooth can you help me. My new code :

import android.support.v4.view.ViewPager;
import android.view.animation.Animation;
import android.view.animation.Transformation;

import java.util.Calendar;

public class ScrollToAnimation extends Animation {
    private int currentIndex = 0, nbChilds = -1, deltaT = 0;
    private float fromX, toX;
    private long animationStart;
    private ViewPager viewpager;

    public ScrollToAnimation(ViewPager viewpager, float fromX, float toX, int duration) {
        this.viewpager = viewpager;
        this.fromX = fromX;
        this.toX = toX;

        nbChilds = viewpager.getChildCount();
        deltaT = duration / nbChilds;

        setDuration(duration);
        animationStart = Calendar.getInstance().getTimeInMillis();
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        super.applyTransformation(interpolatedTime, t);
        int offset = (int) (-fromX * interpolatedTime + fromX);
        viewpager.scrollTo(offset, 0);

        long animationProgression = Calendar.getInstance().getTimeInMillis() - animationStart;
        currentIndex = (int) (animationProgression/deltaT);
        if(viewpager.getCurrentItem() != currentIndex) {
            viewpager.setCurrentItem(nbChilds-currentIndex, false);
        }
    }
}

The ViewPager :

import android.content.Context;
import android.graphics.Canvas;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.animation.Animation;
import android.view.animation.Interpolator;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class CarouselViewPager extends ViewPager {
    private DisplayMetrics metrics;
    private Animation animation;
    private SpeedScroller mScroller = null;
    private boolean animationNotStarted = true, leftToRight;

    public CarouselViewPager(Context context) {
        super(context);
        postInitViewPager();
        metrics = getContext().getResources().getDisplayMetrics();
    }

    public CarouselViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        postInitViewPager();
        metrics = getContext().getResources().getDisplayMetrics();
    }

    private void postInitViewPager() {
        try {
            Class<?> viewpager = ViewPager.class;
            Field scroller = viewpager.getDeclaredField("mScroller");
            scroller.setAccessible(true);
            Field interpolator = viewpager.getDeclaredField("sInterpolator");
            interpolator.setAccessible(true);

            mScroller = new SpeedScroller(getContext(), (Interpolator) interpolator.get(null));
            scroller.set(this, mScroller);
        } catch (Exception e) {
            Log.e("postInitViewPager", e.getMessage());
        }
    }

    public void setScrollDurationFactor(double scrollFactor) {
        mScroller.setScrollDurationFactor(scrollFactor);
    }

    @Override
    public void setCurrentItem(int item, boolean smoothScroll) {
        try {
            Method method = ViewPager.class.getDeclaredMethod("setCurrentItemInternal", int.class, boolean.class, boolean.class, int.class);
            method.setAccessible(true);
            method.invoke(this, item, true, false, 1500);
        } catch (Exception e) {
            e.printStackTrace();
            super.setCurrentItem(item, smoothScroll);
        }
    }

    public void startAnimation(boolean leftToRight) {
        animation = new ScrollToAnimation(this, ((metrics.widthPixels/2)+200)*2, 0, 2000);
        animationNotStarted = false;
        this.leftToRight = leftToRight;
    }

    private Canvas enterAnimation(final Canvas c) {
        animationNotStarted = true;
        startAnimation(animation);
        scrollTo(0, 0);
        return c;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (!animationNotStarted) {
            canvas = enterAnimation(canvas);
        }
        super.onDraw(canvas);
    }
}

Edit2 :

Here a screenshot to help you to understand what I want. Actually I have a custom viewpager like this :

enter image description here

The animation I want is the follow :

  • When I launch the animation the item are far away.
  • After, they come from the left to te right (or the opposite) and stop to the selected item, but I want to have the scale effect when the items are scrolling.
  • I succeed to create the scaling effect thanks to an custom adapter

My issue, here is when I set the current item it's not smooth, do you have any idea ? Here is the code adapter

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.ArrayList;

public class CarouselAdapter extends FragmentPagerAdapter implements ViewPager.OnPageChangeListener {
    private float scale;
    private MainActivity context;

    private FragmentManager fragmentManager;
    private ArrayList<Entity> entities = new ArrayList<>();
    private ScaledFrameLayout cur = null, next = null;

    public CarouselAdapter(MainActivity context, FragmentManager fragmentManager, ArrayList<Entity> mData) {
        super(fragmentManager);
        this.fragmentManager = fragmentManager;
        this.context = context;
        this.entities = mData;
    }

    @Override
    public Fragment getItem(int position) {
        if (position == MainActivity.FIRST_PAGE) {
            scale = MainActivity.BIG_SCALE;
        } else {
            scale = MainActivity.SMALL_SCALE;
        }
        Fragment fragment = CarouselFragment.newInstance(context, entities.get(position), position, scale);
        return fragment;
    }

    @Override
    public int getItemPosition(Object object) {
        return super.getItemPosition(object);
    }

    @Override
    public int getCount() {
        return entities.size();
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        if (positionOffset >= 0f && positionOffset <= 1f) {
            cur = getRootView(position);
            cur.setScaleBoth(MainActivity.BIG_SCALE - MainActivity.DIFF_SCALE * positionOffset);

            if (position < entities.size()-1) {
                next = getRootView(position + 1);
                next.setScaleBoth(MainActivity.SMALL_SCALE + MainActivity.DIFF_SCALE * positionOffset);
            }
        }
    }

    @Override
    public void onPageSelected(int position) { }

    @Override
    public void onPageScrollStateChanged(int state) {}

    private ScaledFrameLayout getRootView(int position) {
        return (ScaledFrameLayout) fragmentManager.findFragmentByTag(this.getFragmentTag(position)).getView().findViewById(R.id.rootItem);
    }

    private String getFragmentTag(int position) {
        return "android:switcher:" + context.carousel.getId() + ":" + position;
    }
}

A more simply way, would be to change the current position of the current item without refresh everything, is it possible ? I mean without making any transition because as you can see I already have the translation and when I set the current item it's result with a conflict with my scrollto with the offset.

like image 295
zed13 Avatar asked Apr 11 '16 13:04

zed13


2 Answers

I think you have to make one of imageSlider with sooth scroll and image change with animation.

Android Image Slider library available in github now see below step to use it.

  • step 1: Gradle in compile below lib.

    dependencies {
    compile "com.android.support:support-v4:+"
    compile 'com.squareup.picasso:picasso:2.3.2'
    compile 'com.nineoldandroids:library:2.4.0'
    compile 'com.daimajia.slider:library:1.1.5@aar'
    }
    
  • Step 2: Add permissions (if necessary) to your AndroidManifest.xml

     <!-- if you want to load images from the internet -->
     <uses-permission android:name="android.permission.INTERNET" /> 
    
     <!-- if you want to load images from a file OR from the internet -->
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    
  • Step 3:Add the Slider to your layout:

    <com.daimajia.slider.library.SliderLayout
    android:id="@+id/slider"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    />
    

    Now Make code in your Activity Here SlideShow.class in manage Code.

     public class SlideShow extends Activity {
         ImageView mIVmenu;
         SliderLayout sliderLayout;
         ListView menu_list;
         ArrayList<String> imgList = new ArrayList<String>();
         int position;
         Button btnBack;
         static int adapter_position = 0;
         String animation_name;
    
         @Override
         protected void onCreate(Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
             setContentView(R.layout.slideshow);
             sliderLayout = (SliderLayout) findViewById(R.id.sliderlayout);
             menu_list = (ListView) findViewById(R.id.menu_list);
             btnBack = (Button) findViewById(R.id.btn_back_slideshow);
             menu_list.setAdapter(adapter);
             // get Data from Intent array list and set on array list
             imgList = getIntent().getStringArrayListExtra("arrayList");
             position = getIntent().getExtras().getInt("position");
            animation_name = SliderLayout.Transformer.Default.toString();
         }
    
        // call method for set images in slideshow and configure slideshow..
       addImagesToSlider();
    
       btnBack.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent i = new Intent(SlideShow.this, MainActivity.class);
            startActivity(i);
            finish();
        }
    });
    
    }
    
     private void addImagesToSlider() {
        for (int i = 0; i < imgList.size(); i++) {
        TextSliderView textSliderView = new TextSliderView(this);
        textSliderView.description("").image(new File(imgList.get(i))).setScaleType(BaseSliderView.ScaleType.CenterInside).setOnSliderClickListener(new BaseSliderView.OnSliderClickListener() {
            @Override
            public void onSliderClick(BaseSliderView slider) {
            }
        });
        sliderLayout.addSlider(textSliderView);
       }
    
    sliderLayout.setPresetTransformer(animation_name);
    sliderLayout.setCustomAnimation(new DescriptionAnimation());
    sliderLayout.stopAutoCycle();
    sliderLayout.setCurrentPosition(position);
    }
    
    BaseAdapter adapter = new BaseAdapter() {
    @Override
    public int getCount() {
        return SliderLayout.Transformer.values().length;
    }
    
    @Override
    public Object getItem(int position) {
        return null;
    }
    
    @Override
    public long getItemId(int position) {
        return 0;
    }
    
    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
    
        View view;
        view = LayoutInflater.from(parent.getContext()).inflate(R.layout.slidemenu_item, parent, false);
        TextView tv = (TextView) view.findViewById(R.id.txtslideTitle);
        final String str = SliderLayout.Transformer.values()[position].toString();
        tv.setText(str);
    
        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
    
                sliderLayout.setPresetTransformer(str);
                animation_name = str;
                notifyDataSetChanged();
    
            }
        });
        if (str.equals(animation_name)) {
            adapter_position = position;                        
    tv.setBackgroundColor(getResources().getColor(R.color.colorAccent));
        } else {  tv.setBackgroundColor(getResources().getColor(R.color.colorPrimaryDark));
        }
        return view;
    }
        };
    }
    

And more information refer this

like image 167
Ravi Vaghela Avatar answered Oct 05 '22 09:10

Ravi Vaghela


Try to use smooth View Pager, you can configure it's speed. All you need is to set it to 0 position, then make it visible, and then move it to target position, he will scroll smoothly to the target, you may apply any animation as in common view pager if you want. Also you may setPagingEnable to false and user will not scroll it by touch

public class SmoothScrollViewPager extends ViewPager {
    private boolean enabled = true;
    public SmoothScrollViewPager(Context context, AttributeSet attrs) {
        super( context, attrs );
        setMyScroller();
    }

    private void setMyScroller() {
        try {
            Class<?> viewpager = ViewPager.class;
            Field scroller = viewpager.getDeclaredField("mScroller");
            scroller.setAccessible(true);
            scroller.set(this, new MyScroller(getContext()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (this.enabled) {
            return super.onTouchEvent(event);
        }

        return false;
    }

    public class MyScroller extends Scroller {
        public MyScroller(Context context) {
            super(context, new DecelerateInterpolator());
        }

        @Override
        public void startScroll(int startX, int startY, int dx, int dy, int duration) {
            super.startScroll(startX, startY, dx, dy, 1000 /*1 secs*/);
        }

    }

    public void setPagingEnabled(boolean enabled) {
        this.enabled = enabled;
    }
}
like image 20
Wackaloon Avatar answered Oct 05 '22 08:10

Wackaloon