I have implemented from the documentation of viewpager2 the follow animation
private const val MIN_SCALE = 0.85f
private const val MIN_ALPHA = 0.5f
class ZoomOutPageTransformer : ViewPager2.PageTransformer {
override fun transformPage(view: View, position: Float) {
view.apply {
val pageWidth = width
val pageHeight = height
when {
position < -1 -> { // [-Infinity,-1)
// This page is way off-screen to the left.
alpha = 0f
}
position <= 1 -> { // [-1,1]
// Modify the default slide transition to shrink the page as well
val scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position))
val vertMargin = pageHeight * (1 - scaleFactor) / 2
val horzMargin = pageWidth * (1 - scaleFactor) / 2
translationX = if (position < 0) {
horzMargin - vertMargin / 2
} else {
horzMargin + vertMargin / 2
}
// Scale the page down (between MIN_SCALE and 1)
scaleX = scaleFactor
scaleY = scaleFactor
// Fade the page relative to its size.
alpha = (MIN_ALPHA +
(((scaleFactor - MIN_SCALE) / (1 - MIN_SCALE)) * (1 - MIN_ALPHA)))
}
else -> { // (1,+Infinity]
// This page is way off-screen to the right.
alpha = 0f
}
}
}
}
}
Now, in my activity I wraped this animation with a Handler to automatically swipe, but is going really fast that I cant even notice when its sliding
private fun slideViewPager(){
var currentPage = 0
var timer: Timer? = null
val DELAY_MS: Long = 2000 //delay in milliseconds before task is to be executed
val PERIOD_MS: Long = 3000
val handler = Handler()
val update = Runnable {
if (currentPage == NUM_PAGES - 1) {
currentPage = 0
}
viewPager.setCurrentItem(currentPage++, true)
}
timer = Timer() // This will create a new Thread
timer!!.schedule(object : TimerTask() { // task to be scheduled
override fun run() {
handler.post(update)
}
}, DELAY_MS, PERIOD_MS)
}
I have adjusted the delay from the handler, but is not that the problem, because that just delays when its gonna change to the other page, but the transition during this change is really fast, how can I slow it down ?
I have encountered a similar problem when working with ViewPager2. I had two items in my ViewPager, and put the switch to the next item as the action of a button. The first time you press it, the animation is instantaneous, like you describe. However, in my setup, if you press again on it, it scrolls back to the left. Once it does that, the animation works correctly (both left and right).
From what I can tell from your code, in your case you continue to scroll in a single direction - hence you only observe the instantaneous scrolling. Try to play around with it and make it scroll back, instead of only forward. See if the animation appears correctly in that case.
EDIT: If you find that the same behavior applies in your case as well, you can apply a completely inelegant hack:
You can "browse" through your ViewPager's items when you're opening up your activity, as quickly as possible. Then, after going through each item, switch back to the first item and then just apply whatever logic you have now. If you do this, the items will already be "loaded" and the animations will work.
Of course, while you're doing that in the "background", you can display a progress loader when you first get into the activity, and once you've scrolled back to the first item, display your activity. The user will think the activity is "loading", but in reality you will be going through each of your ViewPager's items, effectively "pre-loading" them.
Completely ugly solution, but it should work. I hope someone can come up with a better one than this, as I don't exactly know the reason why the animation isn't playing correctly the first time.
Related
I need to set up a ViewPager with the following requirements:
- at any given time, 3 pages must be visible in the screen
- the center page isn't scaled and the behind pages are 60% of the center page;
- center page, must overlap a bit the behind pages.
From what I saw in other questions I've tried to do this:
viewPager.setClipToPadding(false);
int padding = (metrics.widthPixels - centerViewSize) / 2;
viewPager.setPadding(padding, 0, padding, 0);
viewPager.setPageMargin(-(padding / 2));
viewPager.setCurrentItem(10);
viewPager.setOffscreenPageLimit(3);
Doing this got me here:
This is what I was expecting. Just need to bring to front the current selected item.
I've then tried to scale the view with:
public static final float SCALED_SIZE = 0.6f;
viewPager.setPageTransformer(false, new PageTransformer() {
#Override
public void transformPage(final View page, final float position) {
if (position < -1) {
page.setScaleX(SCALED_SIZE);
page.setScaleY(SCALED_SIZE);
} else if (position <= 1) {
float scaleFactor = Math.max(SCALED_SIZE, 1 - Math.abs(position));
page.setScaleX(scaleFactor);
page.setScaleY(scaleFactor);
} else {
page.setScaleX(SCALED_SIZE);
page.setScaleY(SCALED_SIZE);
}
}});
But that gives me some problems.
The first item that should be selected is not the correct one.
Animation chopy.
At some points, there are more than 3 pages on the screen.
Scale is from the bottom and I would like to be from the center.
Any idea how I can solve my issues?
use Library UltraViewPager. It have very nice effects.
My goal is to have a sliding view on fragment 1 which slides a set distance before fragment 2 is pulled into visual view.
I made a visual here that shows what I am trying to do:
Pic 1 Shows the default view of fragment 1 (pink) and sliding view (green), nothing has happened in this state.
Pic 2 The sliding view is able to slide to it's cutoff (black line). It cannot move past this on this fragment.
Pic 3 The entire fragment 1 begins to slide, fragment 2 (blue) is now starting to be pulled into the view
Pic 4 Both fragments continue to slide as before.
Pic 5 Fragment 2 has now slid into view.
When the user tries to return to the previous screen the transition happens in reverse.
Right now I have implemented a ViewPager which hosts the fragments 1 and 2. The default ViewPager behavior allows me to slide between the two fragments, but I am unsure how to implement the functionality I have described.
I was able to achieve the desired transition with the use of a ViewPager PageTransformer
I am using Xamarin.Android in my project, so C# is used. Although this snippet is in C# it could easily be ported to Java code for use in other projects.
float passpoint = 7/8f;
public void TransformPage(View view, float position)
{
var pageWidth = view.Width;
var slidingGap = pageWidth - pageWidth * passpoint;
var translation = position * pageWidth;
if (position < -1)
{ // [-Infinity,-1)
// This page is way off-screen to the left.
view.Alpha = 0;
}
else if (position <= 1)
{ // [-1,1]
var r = new Rect();
//if valid, this view is the startpage
Button button = (Button)view.FindViewById(Resource.Id.slidingButton);
if (button != null)
{
var posPassPoint = -(1 - passpoint);
float ratio;
//create sliding gap
if (position > posPassPoint)
{
ratio = RatioBetween(position, posPassPoint, 0);
button.TranslationX = slidingGap * -ratio;
}
//compensate for sliding gap after it has been reached
else
{
//1- bc want the ratio to shrink
ratio = 1-RatioBetween(position, -1, posPassPoint);
}
view.TranslationX = slidingGap * ratio;
}
//valid on views other than start page (no sliding button)
if (button == null)
{
float ratio;
//create sliding gap
if (position >= passpoint)
ratio = RatioBetween(position, passpoint, 1);
//compensate for sliding gap after it has been reached
else
ratio = 1 - RatioBetween(position, 0, passpoint);
view.TranslationX = slidingGap * ratio;
}
}
else
{ // (1,+Infinity]
// This page is way off-screen to the right.
view.Alpha = 0;
}
}
float RatioBetween(float input, float upperBound, float lowerBound)
{
return (input - lowerBound) / (upperBound - lowerBound);
}
I would like to smoothly animate some views Y position based on the user scrolling a bottom sheet.
http://imgur.com/dVBlh83
However the animation is slightly jerky.
This is probably because scrolling a bottomsheet gives me a slideOffset at some interval, which is too infrequent to setTranlationY like I'm currently doing.
Is there a better way to do this.
Bottom sheet callback
BottomSheetBehavior.BottomSheetCallback() {
#Override public void onSlide(#NonNull View bottomSheetView, float slideOffset) {
int offset = (int) (slideOffset * 100);
if (offset > 0) {
scrollingHeaderView.animate(offset);
}
}
});
scrollingHeaderView
public void animate(int offset) {
position = -(offset / 2);
arrow.setTranslationY(offset * ANIMATION_RATIO_ARROW);
detailView.setTranslationY(offset * ANIMATION_RATIO);
}
I have tried using ObjectAnimator to create lots of small animations at each step.
ObjectAnimator.ofFloat(arrow, "translationY", arrow.getTranslationY(), position * ANIMATION_RATIO_ARROW).start();
in case it helps anyone else. I got it looking much better.
First i set the ration by pixel * range of values i'd get. So offset will be 0 -> 100. Mutliplied by the dp i want the view to move
private static int ANIMATION_RANGE = 100;
arrowScale = -(getResources().getDimensionPixelOffset(R.dimen.arrow_distance) / ANIMATION_RANGE);
containerScale = -(getResources().getDimensionPixelOffset(R.dimen.detail_distance) / ANIMATION_RANGE);
then as the value changes i set this using translationY
arrow.setTranslationY(position * arrowScale);
detailView.setTranslationY(position * containerScale);
I also needed a reset method, which animate back to the original position
public void reset() {
arrow.animate().setDuration(100).translationY(0);
detailView.animate().setDuration(100).translationY(0);
}
It seems like a challenging animation, but I have a feeling this can be done very easily. I am trying to achieve an animation between Fragments like below (see 2nd and 3rd quadrant)
Enter and exit are not difficult, but pre-displaying next and previous card's screen and seamless transition to next card is out of my knowledge scope. Please, if anyone has worked on a similar animation, give me some pointers.
EDIT
The official documentation of Android transitions on click i.e. when user clicks page is zoomed out to show last and previous page and swipe moves it to next one. My requirement is to leave the page at zoomed out level and transition on button clicks:
Question: How will be the view default out to x zoom level to show previous next page parts and transition on click.
You can customize the transition animation between fragments using PageTransformer.
ZoomOutPageTransformer
import android.support.v4.view.ViewPager;
import android.view.View;
public class ZoomOutPageTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.85f;
private static final float MIN_ALPHA = 0.5f;
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
int pageHeight = view.getHeight();
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 1) { // [-1,1]
// Modify the default slide transition to shrink the page as well
float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
float vertMargin = pageHeight * (1 - scaleFactor) / 2;
float horzMargin = pageWidth * (1 - scaleFactor) / 2;
if (position < 0) {
view.setTranslationX(horzMargin - vertMargin / 2);
} else {
view.setTranslationX(-horzMargin + vertMargin / 2);
}
// Scale the page down (between MIN_SCALE and 1)
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
// Fade the page relative to its size.
view.setAlpha(MIN_ALPHA +
(scaleFactor - MIN_SCALE) /
(1 - MIN_SCALE) * (1 - MIN_ALPHA));
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
Usage
viewPager.setPageTransformer(true, new ZoomOutPageTransformer());
Official documentation.
Checkout this and this for showing boundaries of near one.
For folks who come to this question looking for similar requirement:
As Anoop suggests, official documentation is great. Simply implement viewPager.PagerTransform and supply the class to your viewPager. Also, transformPage (the implemented function) is very important in animation transition.
Next part, was to show corners of next and previous fragments. This can be acheived through xml of fragments. Reference : Android tip viewpager with protruding children
Hopes this helps someone to create interactive apps.
UPDATE
This post shared by Anoop makes this transformation a breeze. cheers!
friends....
I got a problem with animation in betwen versions...So i will give description about the requirements of my app and problem im facing
1.My consists of animation which consists viewpager.
2.And this animation must work in lower versions such as 2.2.
3.So for this i have found a awsome library ninoldandroid.
4.I have used animation proxy for my animation.
5.It waa working fine in 4.2.
6.But when coming to 2.2 the animation was not working and the viewpager was moving with its default feature.
My code for animation is...
public class DepthPageTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.75f;
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
AnimatorProxy proxy = AnimatorProxy.wrap(view);
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
proxy.setAlpha(0);
} else if (position <= 0) { // [-1,0]
// Use the default slide transition when moving to the left page
proxy.setAlpha(1);
proxy.setTranslationX(0);
proxy.setScaleX(1);
proxy.setScaleY(1);
} else if (position <= 1) { // (0,1]
// Fade the page out.
proxy.setAlpha(1 - position);
// Counteract the default slide transition
proxy.setTranslationX(pageWidth * -position);
// Scale the page down (between MIN_SCALE and 1)
float scaleFactor = MIN_SCALE
+ (1 - MIN_SCALE) * (1 - Math.abs(position));
proxy.setScaleX(scaleFactor);
proxy.setScaleY(scaleFactor);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
proxy.setAlpha(0);
}
}
}
Can u tell what i have to implement to make this anim ation work in 2.2.
If u feel that the question is insuffient please let me know..Thnaq
There is a Animated view pager by jfeinstein JazzyViewPager which is used by nineoldandroid. which work from 2.2.
(Sorry for late replay)