Android development: custom TabLayout, the magic effect is so simple

Preface

Don't say anything, first show the renderings:

Recently, the company UI designed such a tab switching style. As soon as I saw the UI design drawing, I felt pretty good. But after a few seconds, I subconsciously thought that this effect, the tablayout control that comes with Android should not be able to achieve this effect. Suddenly looked at a loss, I still have to customize one! But what about this arc...

At this time, some friends may think that customizing the view is too troublesome. It is better to let the UI directly cut out this arc. There are three tab items in total, Textview, ImageView... This way, arrange them horizontally, and then do appropriate display and Just hide it.

Yes, it is indeed possible, but as a good developer. We still have to prefer custom view drops.

Thinking analysis

(1) From the effect diagram, we can easily analyze that no matter how many tab items there are, there are only these three situations.
The sketch is as follows:

(2) In either case, first we need to draw a background rectangle, which is relatively simple.

(3) The following is the drawing method of the curve, which has been marked in the sketch. Obviously I need 2 control points, so I need to use a third-order Bezier curve! cubicTo

(4) After drawing the graph, how to respond to the click event? We can get the x and y coordinates after clicking on the control in onTouchEvent, and we can judge which tab item the x coordinate is within, and we think that the tab item is clicked.

(5) How to realize the rounded corners of the control? The canvas can be cropped.

Code

After sorting out the ideas, let's write the code:

Situation one (key code):

 //最左边的图形
            Path pathLeft = new Path();


            pathLeft.lineTo(textWidth, 0);

            pathLeft.cubicTo(textWidth + arcControlX, arcControlY, textWidth + arcWidth - arcControlX, viewHeight - arcControlY, textWidth + arcWidth, viewHeight);

            pathLeft.lineTo(0, viewHeight);

            pathLeft.lineTo(0, 0);


            paint.setColor(selectColor);
            canvas.drawPath(pathLeft, paint);

Step description:

  1. First, the coordinates of our starting point are (0, 0), and draw a straight line to the coordinates (textWidth, 0);
  2. Then the third-order Bezier curve, the coordinates of the two control points are 1 (textWidth + arcControlX, arcControlY), coordinates 2 (textWidth + arcWidth-arcControlX, viewHeight-arcControlY), and the end coordinates (textWidth + arcWidth, viewHeight);
  3. Finally draw a straight line to the coordinate point (0, viewHeight), and then to the final origin (0, 0).

A closed path here, just draw it. The same is true in case two and case three, and I won’t talk nonsense anymore.

Situation two (key code):

 //中间的图形
            Path pathCenter = new Path();
            pathCenter.moveTo(tabPosition * textWidth + tabPosition * arcWidth, 0);
            pathCenter.cubicTo(tabPosition * textWidth + tabPosition * arcWidth - arcControlX, arcControlY, tabPosition * textWidth + tabPosition * arcWidth - arcWidth + arcControlX, viewHeight - arcControlY, tabPosition * textWidth + tabPosition * arcWidth - arcWidth, viewHeight);
            pathCenter.lineTo(tabPosition * textWidth + tabPosition * arcWidth + textWidth + arcWidth, viewHeight);
            pathCenter.cubicTo(tabPosition * textWidth + tabPosition * arcWidth + textWidth + arcWidth - arcControlX, viewHeight - arcControlY, tabPosition * textWidth + tabPosition * arcWidth + textWidth + arcControlX, arcControlY, tabPosition * textWidth + tabPosition * arcWidth + textWidth, 0);
            pathCenter.lineTo(tabPosition * textWidth + tabPosition * arcWidth, 0);


            paint.setColor(selectColor);
            canvas.drawPath(pathCenter, paint);

Situation three (key code):

  //最右边的图形
            Path pathRight = new Path();
            pathRight.moveTo(viewWidth, 0);

            pathRight.lineTo(viewWidth - textWidth, 0);


            pathRight.cubicTo(viewWidth - textWidth - arcControlX, arcControlY, viewWidth - textWidth - arcWidth + arcControlX, viewHeight - arcControlY, viewWidth - textWidth - arcWidth, viewHeight);

            pathRight.lineTo(viewWidth, viewHeight);

            pathRight.lineTo(viewWidth, 0);

            paint.setColor(selectColor);
            canvas.drawPath(pathRight, paint);

Drawing of tabtext (key code):

for (int i = 0; i < tabTextList.size(); i++) {
            String strTabText = tabTextList.get(i);
            Rect rectText = new Rect();
            textPaint.getTextBounds(strTabText, 0, strTabText.length(), rectText);
            int strWidth = rectText.width();
            int strHeight = rectText.height();
            if (i == 0) {
                canvas.drawText(strTabText, (textWidth + arcWidth / 2) / 2 - strWidth / 2, viewHeight / 2 + strHeight / 2, textPaint);
            } else if (i == tabTextList.size() - 1) {
                canvas.drawText(strTabText, viewWidth - (textWidth + arcWidth / 2) / 2 - strWidth / 2, viewHeight / 2 + strHeight / 2, textPaint);

            } else {
                canvas.drawText(strTabText, textWidth * i + arcWidth * (i - 1) + (textWidth + 2 * arcWidth) / 2 - strWidth / 2, viewHeight / 2 + strHeight / 2, textPaint);
            }

        }

Tab click processing (key code):

@Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean isHandleClick = false;//是否处理点击事件

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                float x = event.getX();
                float y = event.getY();
                System.out.println("YPKTabLayoutView.onTouchEvent x=" + x + " y=" + y);
                for (int i = 0; i < tabNumber; i++) {
                    if (x <= ((i + 1) * textWidth + i * arcWidth + arcWidth / 2)) {//点击的第一个按钮
                        tabPosition = i;

                        if (onTabClickListener != null) {
                            onTabClickListener.tabSelectedListener(tabPosition);
                        }

                        invalidate();
                        isHandleClick = true;

                        break;
                    }
                }

                return isHandleClick;


            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        return super.onTouchEvent(event);
    }

Step description:

In the onTouchEvent method, we first get the x and y coordinates after clicking the control, and then the for loop determines which tab item the x coordinate is in, and finally in which range, we think that the tab item is clicked, and the callback corresponds The tabPosition will do.

Remote dependent use

One: add dependency

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

allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}

Add the dependency

dependencies {
      implementation 'com.github.dacaoyuan:YPKTabDemo:1.0.2'
}

Two: add in the xml layout

<com.ypk.library.view.YPKTabLayoutView
        android:id="@+id/mYPKTabLayoutView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        app:view_bg_corners="0"
        app:arcControlX="30" />

Three: in the code

val tabTextList: MutableList<String> = ArrayList<String>()

        tabTextList.add("推荐学习");
        tabTextList.add("企业学院");
        tabTextList.add("我的关注");
        mYPKTabLayoutView.setTabTextList(tabTextList);

        mYPKTabLayoutView.addTabSelectedListener { tabPosition ->
            val makeText =
                Toast.makeText(
                    this@MainActivity,
                    "点击了第" + tabPosition + "项",
                    Toast.LENGTH_SHORT
                )
            makeText.setGravity(Gravity.CENTER, 0, 0);
            makeText.show();
        }

Property description

The article is over here. If you have better suggestions for the realization of ideas, please leave a message and correct me.

Source address:

https://github.com/dacaoyuan/YPKTabDemo

At last

Here I also share an Android learning PDF+architecture video+interview document+source notes , advanced architecture technology advanced mind map, Android development interview special materials, advanced advanced architecture materials collected and organized by several big guys .

These are fine materials that I will read again and again in my spare time. Can effectively help everyone master knowledge and understand principles. Of course, you can also use it to check for omissions and improve your competitiveness.

If you need it, you can  get it here

If you like this article, you might as well give me a thumbs-up, leave a message in the comment area or forward and support it~

Guess you like

Origin blog.csdn.net/River_ly/article/details/107228575