preface

Through ViewPager and Bezier curve to achieve an arc advertising rotation diagram.

rendering

Implementation method

To do this, a few lines of code should now do the trick:

Step 1. Add it in your root build.gradle at the end of repositories:

allprojects {
        repositories {
            ...
            maven { url 'https://www.jitpack.io' }
        }
    }Copy the code

Step 2: Add the dependency:

Dependencies {the compile 'com. Making. Simon986793021: SimonArcViewTest: V1.1'}Copy the code

Step 3 create the layout:

<? XML version="1.0 "encoding=" UTF-8 "? > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android " xmlns:tools="http://schemas.android.com/tools " android:layout_width="match_parent " android:layout_height="match_parent  " android:orientation="vertical " tools:context="com.wind.simonarcviewtest.MainActivity "> <com.wind.arcview.HomeBanner  android:layout_width="match_parent " android:layout_height="250dp " android:id="@+id/hb_banner "> </com.wind.arcview.HomeBanner> </LinearLayout>Copy the code

Step 4. use it in Activity

 HomeBanner homeBanner= (HomeBanner) findViewById(R.id.hb_banner);
        homeBanner.setImagesRes(new int[]{R.drawable.banner5,R.drawable.banner5,R.drawable.banner5,R.drawable.banner5});Copy the code

Through the above steps can be achieved.

PS: Here is an additional interface to change the zoom of the image:

ArcImageView arcImageView=new ArcImageView(this); ArcImageView. SetScale (0.5 f);Copy the code

Now let’s analyze the implementation process.

Train of thought

We can divide the arc ViewPager into two parts: 1.ViewPager 2. Arc image

The principle of

The arcs are drawn by a second-order Bezier curve, so let’s start with a second-order Bezier curve.

Second order curve principle:

The second-order curve consists of two data points (A and C) and one control point (B) to describe the curve state, which is roughly as follows:

The red curve in the figure above is the legendary second-order Bezier curve, so how is this red curve generated? Let’s analyze it in one of the states:

Join AB BC and take points D on AB and E on BC so that it satisfies the condition:

Connect DE, take point F, such that:

The obtained point F is a point on the Bezier curve, and the dynamic process is as follows:

PS: The method corresponding to the second-order curve is quadTo

Bessel curves also have first and third order: the point I want to know is here

Drawing a second-order Bezier curve requires three points: a starting point, an end point and a control point. The different position of control point determines the different degree of curve bending. QuadTo (float x1, float y1, float x2, float y2) is used to plot second-order Bezier curves.

The implementation process

1. Realization of arc pictures

Now that we know how second-order Bezier curves work, we just add path to the picture.

Initialize the three points needed for the Bezier curve in onSizaChanged.

protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); this.width = w; this.height = h; this.path.reset(); This. The path. The moveTo (0.0 0.0 F, F); This.path.addrect (0.0f, 0.0f, (float)this.width, (float)(this.height-this.archeight), path.direction.ccw); Enclosing the startPoint. X = 0.0 F; this.startPoint.y = (float)(this.height - this.ArcHeight); this.endPoint.x = (float)this.width; this.endPoint.y = (float)(this.height - this.ArcHeight); this.controlPoint.x = (float)(this.width / 2); this.controlPoint.y = (float)(this.height + this.ArcHeight); this.invalidate(); }Copy the code

Call onDraw directly from onDraw:

 this.path.moveTo(this.startPoint.x, this.startPoint.y);
            this.path.quadTo(this.controlPoint.x, this.controlPoint.y, this.endPoint.x, this.endPoint.y);
            canvas.drawPath(this.path,this.paint);Copy the code

The complete code is as follows:

public class ArcImageView extends android.support.v7.widget.AppCompatImageView { private Paint paint; private PointF startPoint; private PointF endPoint; private PointF controlPoint; private int width; private int height; private int ArcHeight = 50; private Path path; private Bitmap bitmap; Private float mScale = 1.0 f; public ArcImageView(Context context) { super(context); this.init(); } public ArcImageView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); this.init(); } public ArcImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } / / public void setArcHeight(int height) {this.ArcHeight=height; } @param scale */ public void setScale(float scale) {this.mscale =scale; } private void init() { this.paint = new Paint(); this.paint.setAntiAlias(true); StartPoint = new PointF(0.0f, 0.0f); This. endPoint = new PointF(0.0f, 0.0f); this.endPoint = new PointF(0.0f, 0.0f); ControlPoint = new PointF(0.0f, 0.0f); this.controlPoint = new PointF(0.0f, 0.0f); this.path = new Path(); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); this.width = w; this.height = h; this.path.reset(); This. The path. The moveTo (0.0 0.0 F, F); This.path.addrect (0.0f, 0.0f, (float)this.width, (float)(this.height-this.archeight), path.direction.ccw); Enclosing the startPoint. X = 0.0 F; this.startPoint.y = (float)(this.height - this.ArcHeight); this.endPoint.x = (float)this.width; this.endPoint.y = (float)(this.height - this.ArcHeight); this.controlPoint.x = (float)(this.width / 2); this.controlPoint.y = (float)(this.height + this.ArcHeight); this.invalidate(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (bitmap! =null) {Matrix Matrix = new Matrix(); matrix.setScale(mScale, mScale); Shader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); shader.setLocalMatrix(matrix); paint.setShader(shader); this.path.moveTo(this.startPoint.x, this.startPoint.y); this.path.quadTo(this.controlPoint.x, this.controlPoint.y, this.endPoint.x, this.endPoint.y); canvas.drawPath(this.path,this.paint); } } @Override public void setImageResource(@DrawableRes int resId) { bitmap = BitmapFactory.decodeResource(getResources(),resId); Log.i(">>>>> ",">>>> "); }}Copy the code

In the activity call:

 arcImageView= (ArcImageView) findViewById(com.wind.arcview.R.id.iv_img);
        arcImageView.setImageResource(R.drawable.banner5);Copy the code

Let’s see the effect:

2. The realization of the ViewPager

Here is a custom Banner, inherited from FrameLayout. Then the image uses the arc-shaped image we mentioned above, plus the ViewPager, to achieve the arc-shaped ViewPager. This encapsulates the entire implementation of ViewPager and provides an external interface for use. In addition, since it is an advertising round, it is natural to play automatically, so thread is used here to delay. You can achieve the effect of automatic playback.

External interface add image resource:

 private void initImgFromRes(int[] imagesRes) {
        count = imagesRes.length;
        for (int i = 0; i < count; i++) {
            ImageView iv_dot = new ImageView(context);
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.WRAP_CONTENT,
                    LinearLayout.LayoutParams.WRAP_CONTENT);
            params.leftMargin = 5;
            params.rightMargin = 5;
            iv_dot.setImageResource(R.drawable.dot_blur);
            ll_dot.addView(iv_dot, params);
            iv_dots.add(iv_dot);
        }
        iv_dots.get(0).setImageResource(R.drawable.dot_focus);

        for (int i = 0; i <= count + 1; i++) {
            View banner_view = LayoutInflater.from(context).inflate(R.layout.banner_content_layout, null);
            ArcImageView imageView_banner_title = (ArcImageView) banner_view.findViewById(R.id.iv_img);
            if (i == 0) {
                imageView_banner_title.setImageResource(imagesRes[count - 1]);
            } else if (i == count + 1) {
                imageView_banner_title.setImageResource(imagesRes[0]);
            } else {
                imageView_banner_title.setImageResource(imagesRes[i - 1]);
            }
            views.add(banner_view);
        }
        setAtt();
    }Copy the code

This is the main implementation.

GitHub

github

If you think it’s helpful, you can hit star.