preface

We’ve seen more and more ViewPager card effects recently, even in our own products. Just as when I saw this effect, my heart thought is that this is simple, github searched a large number of baskets, I saw no less than 4 libraries, it is more troublesome to use, not to say that it is not written well, are pioneers in this respect, worth learning. The key is that in the era of one small requirement in three days and one big requirement in a week, how can we complete the task without one line of code, let alone reflect the force of our excellent programmers! Just kidding, ha ha! I’ve wrapped up common card effects so they can be used in a line of code. No picture, say a J8! Full use of graphic form analysis, to help you understand.

Method of use

viewPager.bind(getSupportFragmentManager(), new MyCardHandler(), Arrays.asList(imageArray));Copy the code

So ViewPager is our own custom one called CardViewPager. One of the things that might get messy is MyCardHandler.

public class MyCardHandler implements CardHandler { @Override public View onBind(final Context context, final String data, final int position) { View view = View.inflate(context, R.layout.item, null); ImageView imageView = (ImageView) view.findViewById(R.id.image); Glide.with(context).load(data).into(imageView); view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(context, "data:" + data + "position:" + position, Toast.LENGTH_SHORT).show(); }}); return view; } } public interface CardHandler { View onBind(Context context, T data, int position); }Copy the code

You can manipulate your View in onBind, which provides the data and the View’s index. Just like the getView of ListView.

Almost. That’s how it works. But ten minutes on stage, ten years off stage.

The effect

The principle of analytic

In terms of visual effects, the card is the first to be seen, followed by the two cards that peep out from the left and right of the card. Card effects are a no-brainer, CradView. I left the encapsulation of this control at the end, because we are completely open to views, and as long as we have this sliding effect, we can fill any view, not just CardView, and I would recommend a few more layout effects for views.

Let’s take a look at how these two guys in the dark pull it off.

This is our most common ViewPager effect.

PageTransformer

So let’s see what happens.

I don’t know if you guys can see this? I can see that the first ViewPager is zooming out and offsetting to the right, and the second ViewPager is zooming in and offsetting to the left. WTF? Zooming I see, isn’t the first one moving to the left? You told me to move right?

Students, please put down your hand of the kitchen knife, listen to me carefully, we first look at the source code.

@Override public void transformPage(View page, float position) { if (mViewPager == null) { mViewPager = (ViewPager) page.getParent(); } int leftInScreen = page.getLeft() - mViewPager.getScrollX(); int centerXInViewPager = leftInScreen + page.getMeasuredWidth() / 2; int offsetX = centerXInViewPager - mViewPager.getMeasuredWidth() / 2; Float offsetRate = (float) offsetX * 0.38 f/mViewPager getMeasuredWidth (); float scaleFactor = 1 - Math.abs(offsetRate); if (scaleFactor > 0) { page.setScaleX(scaleFactor); page.setScaleY(scaleFactor); page.setTranslationX(-mMaxTranslateOffsetX * offsetRate); }}Copy the code

This is the core method of PageTransformer, directly say you may be more senseless, adhering to the style of graphic, let’s take a look at the two pictures, the picture is stolen, there are ready-made why do it yourself, even if you don’t think so now, in a few years will think so, I bet half a pack of spicy sticks.

This is the basis for you to customize all the cool toggle effects of a ViewPager. A view is a view filled with a ViewPager or a view filled with a fragment. It is clear from the above that students can play by themselves. Only when they play by themselves can they know what is a waste of time.

Now, let’s analyze why the library is written this way. Get the ViewPager reference, null is used to prevent repeated fetchings. Why page. GetParent gets the ViewPager LinearLayout? Because it has destruction and creation).

LeftInScreen, Page.getLeft () represents how far the current view is from its parent (ViewPager) to the left, mViewPage.getScrollx () represents how far the ViewPager slides along the X-axis (content), So, obviously, the leftInScreen is the distance from the left of the view to the left of the current view(the ViewPager’s current Item).

CenterXInViewPager consists of the leftInScreen plus half the width of the view, starting at the middle of the view.

OffsetX is relatively convoluted, but it’s the heart of it. It is made by centerXInViewPager plus half the width of the ViewPager. In general, offsetX and leftInScreen are equal. Adding half and subtracting half makes a difference, but the half is not necessarily equal, such as ViewPager plus padding. If you understand the above parsing, it’s simple: the view’s offset relative to the current item.

Those of you with a strong spatial imagination already understand this, but I’m sure I’ll take care of all of you. Here’s a picture for you to look at to understand the concepts above.

The former is the ratio of offsetX to ViewPager, while the latter uses the absolute value of math. abs because the values returned above are positive and negative, left and right are positive.

I don’t want to say more about the final property modification, as a believer Android programmer, this is not known, I will choose to forgive you. And the thing that’s kind of stuck here is why setTranslationX, is because we called setScaleX, you think you scaled, did you leave a little space in the middle? So this is just filling the gap in the middle, making it look like it’s always connected, and you can change it, but we’re at a maximum of 180dp, and that’s why I said the first one was moving to the right.

setPageTransformer(false, new CardTransformer(context));Copy the code

That’s it. Let me explain, the first parameter, our library doesn’t really matter, but as a programmer with a high standard, I’m sorry I didn’t ask.

* @param reverseDrawingOrder true if the supplied PageTransformer requires page views
*                            to be drawn from last to first instead of first to last.Copy the code

If it is false, draw from the first page to the last page. If it is true, draw from the last page to the first page.

PageTransformer allows you to design cool switch animations, such as stereo flip, fade in and out, and so on.

You can also take a look at the elder brother “Android to achieve personality ViewPager switch animation combat PageTransformer (compatible with Android3.0 below)”

ViewPager

Our main characters are the two guys watching, so the main characters are going to make an appearance. Now we want the ViewPgaer to set aside two areas to display them. Remember, at the beginning, I asked you to think of the ViewPager as a LinearLayout, and I’m going to do that again. The ViewPager display view by default only shows the current Item, but we just squeeze the content, and the common squeezing is the padding, Those of you who looked closely at the top would have guessed it. I’ve set the 40DP padding here to see what it looks like.

The first parameter is false, and the right parameter covers the left, which also confirms our conclusion. The latter is because we didn’t add the clipToPadding property to false. Just look at the name, do you have a clipping padding? So let’s see what happens.

If a little mean, between the view and open point is perfect, so we just use the padding, might as well use margin, as the saying goes, not in charge of foreign affairs should ask margin, never doesn’t ask padding, familiar, but as a problem where, no trouble, is such, circle, that is the point.

int margin = typedArray
                .getDimensionPixelOffset(R.styleable.CardViewPager_card_margin,
                        (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 40, displayMetrics));
setPageMargin(margin);Copy the code

Look at the final result.

I’m not going to talk about how to use the CardView, but I’ve also provided a customizable aspect ratio CardView that supports shadows by default, but one thing to note is that if you’re using your own CardView, you’d better add it

app:cardPreventCornerOverlap="true"
app:cardUseCompatPadding="true"Copy the code

After 5.0 the default is false, which means shadows are not supported (they are covered).

Adapter

To analyze how to build the view now, here we use fragments, because Google is for us to deal with a lot of loading problem, use it is that here we adapter inherits from FragmentStatePagerAdapter, because we probably many CARDS.

Take a look at the core code:

Context context = getContext(); List cardItems = new ArrayList(); for (int i = 0, size = data.size(); i < size; i++) { T t = data.get(i); CardItem item = new CardItem(); item.bindHandler(handler); item.bindData(t, i); cardItems.add(item); } if (mHandler == null) { throw new RuntimeException("please bind the handler !" ); } return mHandler.onBind(mContext, mData, mPosition);Copy the code

Here we adopt mHandler to reconstruct the View, rather than reusing constructed out of View, is used with FragmentStatePagerAdapter, better use of resources and release resources, otherwise it is easy to cause OOM.

conclusion

That’s about it. I’m sure you have a lot of questions and a lot of ideas. These questions are not about the concepts I outlined above, but rather about the ViewPager that you might already be able to implement in a different way, or that you might already be typing code that you wanted to design but didn’t implement. If it helps you a little, then my purpose will be met.

portal

GitHub:github.com/crazysunj/C…

Blog: One line of code to implement the ViewPager card effect