Simulation and distortion of the principle of the Android page flip Effect

Source: Internet
Author: User

Simulation and distortion of the principle of the Android page flip Effect

Respect Original reprinted Please note: From AigeStudio (http://blog.csdn.net/aigestudio) Power by Aige infringement must be investigated!

ArtilleryTown Building

In the previous section, we achieved the page turning curve, but the effect was a little flawed:


, We found that the fold area is strange and did not achieve our previous "bending" effect. Why? Is the calculation incorrect? Actually, it is not. We used to color the canvas during the previous test, but here we use a bitmap. Although our Path is a curve and Region has a curve area, however, our Bitmap is a regular rectangle. How can we bend it ~ What should we do? Speaking of distortion, we first think of the drawBitmapMesh method, which is the only API we know now that can distort images, however, the drawBitmapMesh method can also be used in a variety of ways. The simplest is to maximize the constant sub-value and divide the image into a certain grid area, then, determine the subdivision line closest to the curve start point and the vertex to obtain the subdivision line intersection point in the region and gradually move the distance value between the starting point and the vertex in the specified direction in percent. This method is simple and crude, but the distortion is not very accurate. To be accurate, the accuracy depends on the subdivision. The more precise the subdivision, the higher the performance consumption. The second method is to dynamically generate the score based on the starting point and vertex of the curve, we can ensure that there is a subdivision line at the starting point and the vertex, so that we can accurately calculate the distortion range, but it is quite troublesome to calculate the fine score dynamically, which one is used? In view of the time relationship, we try to use the first method. First, we define the width and height of the sub-score:

Private static final int SUB_WIDTH = 19, SUB_HEIGHT = 19; // 19 grids in each column
The 19 grids divide the controls into 20x20 Mesh Subdivision lines. Then we do not need to use drawBitmap to draw the folding area, but instead use drawBitmapMesh. When talking about 1/6, some friends used small windows for many times. What do I mean by off-screen buffering? Here I am entitled to demonstrate it, use a separate Bitmap when creating a distorted image and load it into an additional Canvas:

Private Canvas mCanvasFoldCache; // execute the Canvasprivate Bitmap mBitmapFoldCache command to draw the off-screen buffer; // store the Bitmap of the off-screen buffer data.
In the constructor, We instantiate mCanvasFoldCache:

/** Instantiate Canvas */mCanvasFoldCache = new Canvas ();
In onSizeChanged, we generate mBitmapFoldCache:

/*** Generate a buffer Bitmap and inject it into Canvas */mBitmapFoldCache = Bitmap. createBitmap (mViewWidth + 100, mViewHeight + 100, Bitmap. Config. ARGB_8888); mCanvasFoldCache. setBitmap (watermark );
Here, the purpose of + 100 is to make Bitmap have extra space to plot the distorted part of the image. We have said that the size of the Canvas actually depends on the Bitmap loaded internally. If we do not add more than 100, the size of mBitmapFoldCache is just as large as that of our controls, but the distorted image is out of this range:


For example, the transparent red range is the size of our mBitmapFoldCache, but the distortion at the bottom and right is not included. to compensate for this loss, I will increase the width and height of mBitmapFoldCache by 100, of course, you can also calculate the specific value, which is only used for demonstration here.

When drawing, we first draw all the data to mBitmapFoldCache and then draw the Bitmap to our canvas:

mCanvasFoldCache.drawBitmapMesh(mBitmaps.get(end - 1), SUB_WIDTH, SUB_HEIGHT, mVerts, 0, null, 0, null);canvas.drawBitmap(mBitmapFoldCache, 0, 0, null);
It should be noted that our mBitmapFoldCache is generated in the onSizeChanged method and will not be regenerated every time we draw the image. That is to say, each painting is actually superimposed on the previous drawing data, this will bring us a problem. Although the display results may not be wrong, it is necessary to constantly calculate the number of pixels in front of each painting, which will definitely affect the performance, in this case, we want to clear the content in mBitmapFoldCache before drawing each result:

mCanvasFoldCache.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);mCanvasFoldCache.drawBitmapMesh(mBitmaps.get(end - 1), SUB_WIDTH, SUB_HEIGHT, mVerts, 0, null, 0, null);canvas.drawBitmap(mBitmapFoldCache, 0, 0, null);
So far, we don't need to buffer the rendering, but simply use drawBitmapMesh:

canvas.drawBitmapMesh(mBitmaps.get(end - 1), SUB_WIDTH, SUB_HEIGHT, mVerts, 0, null, 0, null);
The focus is on how to generate these distortion points. In the constructor, We instantiate the coordinate array:

// Instantiate the array and initialize the default array data mVerts = new float [(SUB_WIDTH + 1) * (SUB_HEIGHT + 1) * 2];
After calculating the coordinate of each point of the curve, we generate the distorted coordinate:

If (sizeLong> mViewHeight) {// omitting a large amount of code ......} Else {// omitting huge amounts of code ...... /** Generate the distorted coordinates of the collapsed area */int index = 0; for (int y = 0; y <= SUB_HEIGHT; y ++) {float fy = mViewHeight * y/SUB_HEIGHT; for (int x = 0; x <= SUB_WIDTH; x ++) {float fx = mViewWidth * x/SUB_WIDTH; mVerts [index * 2 + 0] = fx; mVerts [index * 2 + 1] = fy; index + = 1 ;}}}
Although we have generated a coordinate array above, there is no distorted image. Before proceeding to the next step, let's analyze how to distort it, when we draw a Bitmap using drawBitmapMesh in the folding area, the image is essentially divided by a grid:


Our method is actually very simple. You just need to drag the point from the short side length minus the short side length multiplied by the position of 1/4 to the short side length position progressively down, right:


The two blue points shown in Figure represent the position where the length of the short side is reduced by the length of the short side multiplied by 1/4 and the length of the short side, because our grid is unchanged, but the position is constantly changing, we should obtain the grid point closest to the current position. For example, for two blue points in the current position, we should obtain the corresponding position in the grid:


For better tolerance values, let's move the start point back to the end point and move it forward to the end point. The final trade-off is as follows:


The same is true on the right:


The implementation in the Code is also very simple:

// Calculate the starting subdivision subscript of the bottom distortion. mSubWidthStart = Math. round (btmX/mSubMinWidth)-1; mSubWidthEnd = Math. round (btmX + CURVATURE * sizeShort)/mSubMinWidth) + 1; // calculate the starting subdivision subscript of the right-side distortion (mSubHeightStart = (int) (leftY/mSubMinHeight)-1; mSubHeightEnd = (int) (leftY + CURVATURE * sizeLong/mSubMinHeight) + 1;
We only need to drag the mSubWidthStart point to the mSubWidthEnd point, and the mSubHeightStart point to the mSubHeightEnd point to the right to achieve the initial "Twist" effect, right, however, this drag is exquisite. First, the drag distance doubles,


The offset value of each vertex doubles as compared to the previous vertex. How much is the offset? It is based on the largest offset value. to simplify the problem, I will not calculate it, but give a fixed starting value and doubling rate:

// Float offsetLong = CURVATURE/2F * sizeLong; // float mulOffsetLong = 1.0F; // float offsetShort = CURVATURE/2F * sizeShort; // float mulOffsetShort = 1.0F;
At this time, we can consider starting to calculate the distorted coordinates:

// Calculate the starting subdivision subscript of the bottom distortion. mSubWidthStart = Math. round (btmX/mSubMinWidth)-1; mSubWidthEnd = Math. round (btmX + CURVATURE * sizeShort)/mSubMinWidth) + 1; // calculate the starting subdivision subscript of the right-side distortion (mSubHeightStart = (int) (leftY/mSubMinHeight)-1; mSubHeightEnd = (int) (leftY + CURVATURE * sizeLong/mSubMinHeight) + 1;/** generate distorted coordinates of the collapsed area */int index = 0; // float offsetLong = CURVATURE/2F * sizeLong; // float mulOffsetLong = 1.0F; // float offsetShort = CURVATURE/2F * sizeShort; // float mulOffsetShort = 1.0F; for (int y = 0; y <= SUB_HEIGHT; y ++) {float fy = mViewHeight * y/SUB_HEIGHT; for (int x = 0; x <= SUB_WIDTH; x ++) {float fx = mViewWidth * x/SUB_WIDTH;/** right twist */if (x = SUB_WIDTH) {if (y> = mSubHeightStart & y <= mSubHeightEnd) {fx = mViewWidth * x/SUB_WIDTH + offsetLong * mulOffsetLong; mulOffsetLong = mulOffsetLong/1.5F ;}} /** bottom Twist */if (y = SUB_HEIGHT) {if (x> = mSubWidthStart & x <= mSubWidthEnd) {fy = mViewHeight * y/SUB_HEIGHT + offsetShort * mulOffsetShort; mulOffsetShort = mulOffsetShort/1.5F;} mVerts [index * 2 + 0] = fx; mVerts [index * 2 + 1] = fy; index + = 1 ;}}
The effect is as follows:


The figure above may not be clearly visible because of the size limit of the upload. If you use DL, I think the project runs, and we can see that the distorted part of the page will be slightly broken during the flip process, the reason is very simple. Our distortion only applies to the last row at the bottom, y = SUB_HEIGHT, And the rightmost column at the right, x = SUB_WIDTH. In fact, the distortion is a pull linkage effect, the distortion will not only affect the last row/column, but also affect the second, third, and fourth rows. However, the effect is decreasing, and this part is left for everyone to do it, I am very clear about the principles.

So far, the next section will improve the final effect and end all Study in this example ~

Source code download: Portal

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.