I want cardview elevation animation just like Google is doing in "PlayGames" animation. Here is a sample gif of animation. Can anyone guide me how to do it or refer any library.
sample gif animation
Thanks
How to do it?
Using Viewpager and Shadow Transform
1- create a PagerAdapter for cardview
2- inside the adapter in instantiateItem method set elevation for the card like this
CardView cardView = (CardView) view.findViewById(R.id.cardView);
if (mBaseElevation == 0) {
mBaseElevation = cardView.getCardElevation();
}
cardView.setMaxCardElevation(mBaseElevation * MAX_ELEVATION_FACTOR);
mViews.set(position, cardView);
return view;
after that implement ViewPager.OnPageChangeListener
inside the onPageScrolled
if (currentCard != null) {
if (mScalingEnabled) {
currentCard.setScaleX((float) (1 + 0.1 * (1 - realOffset)));
currentCard.setScaleY((float) (1 + 0.1 * (1 - realOffset)));
}
currentCard.setCardElevation((baseElevation + baseElevation
* (CardAdapter.MAX_ELEVATION_FACTOR - 1) * (1 - realOffset)));
}
CardView nextCard = mAdapter.getCardViewAt(nextPosition);
// We might be scrolling fast enough so that the next (or previous) card
// was already destroyed or a fragment might not have been created yet
if (nextCard != null) {
if (mScalingEnabled) {
nextCard.setScaleX((float) (1 + 0.1 * (realOffset)));
nextCard.setScaleY((float) (1 + 0.1 * (realOffset)));
}
nextCard.setCardElevation((baseElevation + baseElevation
* (CardAdapter.MAX_ELEVATION_FACTOR - 1) * (realOffset)));
}
full code ViewPagerCards
if you want to do that using RecyclerView
you can get the middle item and check onBindViewHolder if that item is middle item then do the scale animation
to know to get the middle check this answer :
Get center visible item of RecycleView when scrolling
Related
I'm trying to achieve this:
however, while I am able to achieve the Card sliding effect, I am unable to make the cards appear one behind the other like in this picture.
viewPager.setPageTransformer(false, (page, position) -> {
if (position >= 0) {
page.setScaleX(0.7f - 0.05f * position);
page.setScaleY(0.7f);
page.setTranslationX(-page.getWidth() * position);
page.setTranslationY(30 * position);
}
I have a RecyclerView of items and a layoutManager that is of type StaggeredGridLayoutManager. I was in an interesting situation, I wanted my items staggered to look like this:
but my views are all the same size, so they would not stagger. To correct the problem I needed to add an offset at the start of the 2nd column. Since I was also creating my own custom decorator class I figured the best way to accomplish this was to just add an offset for the first right column item in my list using the getItemsOffsets method.
Here is the relevant code for my decorator class:
public class StampListDecoration extends RecyclerView.ItemDecoration {
...
#Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
// good example here: https://stackoverflow.com/questions/29666598/android-recyclerview-finding-out-first-and-last-view-on-itemdecoration/30404499#30404499
/**
* Special case. Te first right side item in the list should have an extra 50% top
* offset so that these equal sized views are perfectly staggered.
*/
if (parent.getChildAdapterPosition(view) == 1) {
/**
* We would normally do a outRect.top = view.getHeight()/2 to create a 50% top offset on the first right item in the list.
* However, problems would arise if we paused the app when the top right item was scrolled off screen.
* In this situation, when we re-inflated the recyclerview since the view was off screen
* Android would say the height of the view was zero. So instead I added code that
* looked for the height of the top most view that was visible (and would therefore
* have a height.
*
* see https://stackoverflow.com/questions/29463560/findfirstvisibleitempositions-doesnt-work-for-recycleview-android
* because as a staggeredGrid layout you have a special case first visible method
* findFirstVisibleItemPositions that returns an array of (notice the S on the end of
* the method name.
*/
StaggeredGridLayoutManager layoutMngr = ((StaggeredGridLayoutManager) parent.getLayoutManager());
int firstVisibleItemPosition = layoutMngr.findFirstVisibleItemPositions(null)[0];
int topPos = 0;
try {
topPos = parent.getChildAt(firstVisibleItemPosition).getMeasuredHeight()/2;
} catch (Exception e) {
e.printStackTrace();
}
outRect.set(0, topPos, 0, 0);
} else {
outRect.set(0, 0, 0, 0);
}
}
}
my problem is that these offsets are not getting saved to state when my activity pauses/resumes. So when I switch to another app and switch back, the right column in my RecyclerView slides back to the top...and I lose my stagger.
Can someone show me how to save my offset state? Where are offsets supposed to be saved? I was assuming the LayoutManager would save this information, and I'm saving the LayoutManager state, but that does not seem to be working.
I have an special use case where I have an an custom FrameLayout which contains 2 custom views. I will call it MyWrapperFL.
I have another custom view, which is outside this custom FrameLayout.
All of this is wrapped inside an basic FrameLayout.
So I have the following:
CustomView 1
MyWrapperFL
CustomView 2
CustomView 3
Now I want to change the order of the views like this:
CustomView 3 (top most)
CustomView 1
CustomView 2 (bottom most)
I've tried using the following utility method I've created:
/**
* Reorder the position of the views on their Z axis.
* <br/>
* The order of the views is important. The first in the list will be the top most view while the last in the list
* will be the bottom most view.
*
* #param views
* The list of views which to reorder. Can be {#code null}.
*/
private void updateViewsOrder(#Nullable View... views) {
if (null == views) {
// No views specified for reorder - exit early
return;
}
List<View> viewList = Arrays.asList(views);
int translationZ = viewList.size();
for (View view : viewList) {
if (null != view) {
view.bringToFront();
view.getParent().requestLayout();
view.invalidate();
}
}
}
But result is not the desired one. Instead of the expected result I get the following:
CustomView 1 (top most)
CustomView 3
CustomView 2 (bottom most)
I'm guessing this is because they have different parents. Can anyone help me with this? Is there a way to do it?
I am trying to implement a vertical swipeable ViewPager with stack of cards like appearance.
I am able to achieve VerticalViewPager using ViewPager.PageTransformer and swapping the touch points.
I am getting following card appearance -
I want to achieve following appearance -
How can I achieve this effect?
Thanks in Advance.
In order to achieve this vertical View Pager without any library dependency
You can follow the steps below :
In your activity_main.xml
<android.support.v4.view.ViewPager
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="600dp"
android:id="#+id/viewpager">
</android.support.v4.view.ViewPager>
In your viewpager_contents.xml
You can create the design that you want according to the above
picture.
Create the adapter and model class to hold the data.
4.In MainActivity.java, after setting the adapter and the pageTransformer add the following code.
private class ViewPagerStack implements ViewPager.PageTransformer {
#Override
public void transformPage(View page, float position) {
if (position >= 0) {
page.setScaleX(0.7f - 0.05f * position);
page.setScaleY(0.7f);
page.setTranslationX(-page.getWidth() * position);
page.setTranslationY(30 * position);
}
}
}
For detailed reference you can watch this video:
CLICK HERE
Hope you will get the output what you needed!!
none of the above solutions worked for me peroperly.
this is my solution :
My PageTransformer class :
class ViewPagerCardTransformer : ViewPager.PageTransformer {
override fun transformPage(page: View, position: Float) {
if (position >= 0) {
page.scaleX = 0.9f - 0.05f * position
page.scaleY = 0.9f
page.alpha = 1f - 0.3f * position
page.translationX = -page.width * position
page.translationY = -30 * position
} else {
page.alpha = 1 + 0.3f * position
page.scaleX = 0.9f + 0.05f * position
page.scaleY = 0.9f
page.translationX = page.width * position
page.translationY = 30 * position
}
}
}
code in my fragment :
val adapter = MyPagerAdapter(pageItems)
viewPager.adapter = adapter
/*below line will increase the number of cards stacked on top of
each other it is set to 1 by default. don't increase it too much as you
will end up with too much view page items in your memory
*/
mDaysViewPager.offscreenPageLimit = 3
viewPager.setPageTransformer(true, ViewPagerCardTransformer())
I'm Using this code for vertical card view stack
https://github.com/AndroidDeveloper98/StackViewPager
You could use the SwipeStack library. It does exactly what you want - it is basically a viewgroup that inflates views based on your adapter implementation, placing them one on top of the other.
The magic is here https://github.com/yuyakaido/CardStackView. You can easily custom what you want. Happy coding :)
How can I implement swipe of one image on another likewise the attached image.
In image one can see that background image is static, and user can able to swipe another image. Its a screenshot of housing.com app.
Can anyone help me in this.
Note: tried for viewpager, jazzyviewpager, Parallex view but no success
Use custom Viewpager(jazzy viewpager library with stack effect and disable zoomout functionality inside this) to acheive this.
So after so many days of search n implementations I got this exactly.
Steps to achieve:
1. Implement Viewpager.
2. User custom view pager with transition.
3. The most important one, Implement clipDrawable to clip drawable on upcoming page on view pager.
Here is the Scale transformation class uses clipdrawable :
public class ScalePageTransformer implements PageTransformer {
private static final float SCALE_FACTOR = 0.95f;
private final ViewPager mViewPager;
public ScalePageTransformer(ViewPager viewPager) {
this.mViewPager = viewPager;
}
#Override
public void transformPage(View page, float position){
View mainLayout = page.findViewById(R.id.bg_rel);
ClipDrawable clipDrawable = (ClipDrawable) mainLayout.getBackground();
if (position <= 0){
// apply zoom effect and offset translation only for pages to
// the left
// final float transformValue = Math.abs(Math.abs(position) - 1) * (1.0f - SCALE_FACTOR) + SCALE_FACTOR;
int pageWidth = mViewPager.getWidth();
final float translateValue = position* -pageWidth;
// page.setScaleX(transformValue);
// page.setScaleY(transformValue);
if (translateValue > -pageWidth){
page.setTranslationX(translateValue);
} else {
page.setTranslationX(0);
}
clipDrawable.setLevel(10000);
} else {
//entering view
int level = (int) ((1 - position) * 10000);
clipDrawable.setLevel(level);
mainLayout.setTranslationX(-1 * position * page.getWidth());
}
}
}
rel_bg: My main layout having drawables.
Hope it helps for somebody.