Android text ads, custom vertical scroll switching TextView

The homepage of many app s will have a banner for displaying hot messages, which dynamically displays messages by vertically switching text. Vertical switching can effectively use the space to display more content, and the dynamic effect can attract the attention of users.

I can think of two ways to achieve this effect:

1. Inherit a LineLayout, add two textviews inside, and realize the movement, display and hiding of TextView through animation.

2. Inherit TextView, draw text manually, and then dynamically change the drawing of text to achieve the dynamic effect of switching.

In contrast, the first method is simpler, and method 1 can not only add TextVIew, but also add two viewgroups, and then build a more complex layout, such as adding pictures. The second way to realize this function is to use the custom control. See the code implementation below:

private static final int DEFAULT_SWITCH_DURATION = 500;
    private static final int DEFAULT_IDLE_DURATION = 2000;
    private Context mContext;
 
    private List<String> lists;//The displayed text content will be cycled
    private int contentSize;
    private String outStr;//Text content currently slid out
    private String inStr;//Text content currently sliding in
    private float textBaseY;//baseline for text display
    private int currentIndex = 0;//Which text is currently displayed
 
    private int switchDuaration = DEFAULT_SWITCH_DURATION;//Switching time
    private int idleDuaration = DEFAULT_IDLE_DURATION;//Interval time
    private int switchOrientation = 0;
 
    private float currentAnimatedValue = 0.0f;
    private ValueAnimator animator;
 
    private int verticalOffset = 0;
    private int mWidth;
    private int mHeight;
    private int paddingLeft = 0;
    private int paddingBottom = 0;
    private int paddingTop = 0;
 
    private Paint mPaint;
 
    //Callback interface, which is used to inform the caller of the current state of the control
    public VerticalSwitchTextViewCbInterface cbInterface;
 
    public VerticalSwitchTextView(Context context) {
        this(context, null);
    }
 
    public VerticalSwitchTextView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
 
    public VerticalSwitchTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.VerticalSwitchTextView);
        try {
            switchDuaration = array.getInt(R.styleable.VerticalSwitchTextView_switchDuaration, DEFAULT_SWITCH_DURATION);
            idleDuaration = array.getInt(R.styleable.VerticalSwitchTextView_idleDuaration, DEFAULT_IDLE_DURATION);
            switchOrientation = array.getInt(R.styleable.VerticalSwitchTextView_switchOrientation, 0);
        } finally {
            array.recycle();
        }
        init();
    }

Firstly, some constants and variables are defined, and three construction methods are implemented.

The meaning of constants can be directly seen from the annotation of the code. The method with only one parameter in the construction method is called when the View is generated by using new in the code. The construction method with two parameters is called when the View is defined in xml. The construction method with three parameters is not often used and will be used when there is a custom style. The custom method will be used in the following construction.

<resources>
    <declare-styleable name="VerticalSwitchTextView">
        <attr name="switchDuaration" format="integer"/>
        <attr name="idleDuaration" format="integer"/>
        <attr name="switchOrientation">
            <enum name="up"  value="0"/>
            <enum name="down"  value="1"/>
        </attr>
    </declare-styleable>
</resources>

The above is the content of user-defined attributes, which correspond to switching duration, switching interval and switching direction respectively.

private void init() {
        setOnClickListener(this);
 
        mPaint = getPaint();
        mPaint.setColor(getCurrentTextColor());
 
        animator = ValueAnimator.ofFloat(0f, 1f).setDuration(switchDuaration);
        animator.setStartDelay(idleDuaration);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                currentAnimatedValue = (float) animation.getAnimatedValue();
                if (currentAnimatedValue < 1.0f) {
                    invalidate();
                }
            }
        });
        animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
 
            }
 
            @Override
            public void onAnimationEnd(Animator animation) {
                currentIndex = (++currentIndex) % contentSize;
                if (cbInterface != null) {
                    cbInterface.showNext(currentIndex);
                }
                outStr = lists.get(currentIndex);
                inStr = lists.get((currentIndex + 1) % contentSize);
 
                animator.setStartDelay(idleDuaration);
                animator.start();
            }
 
            @Override
            public void onAnimationCancel(Animator animation) {
 
            }
 
            @Override
            public void onAnimationRepeat(Animator animation) {
 
            }
        });
    }

An attribute animation is defined in the init() method. The progress of drawing is controlled through the update of attribute values. In the onAnimationUpdate() method of AnimatorUpdateListener, invalidate() is constantly called to trigger the callback of View's onDraw() method. In the onAnimationEnd() method of AnimatorListener, update the content to be displayed, and execute the animation after a certain interval.

    /**
     * Set the text content to be displayed circularly
     *
     * @param content Content list
     */
    public void setTextContent(List<String> content) {
        lists = content;
        if (lists == null || lists.size() == 0) {
            return;
        }
        contentSize = lists.size();
 
        outStr = lists.get(0);
        if (contentSize > 1) {
            inStr = lists.get(1);
        } else {
            inStr = lists.get(0);
        }
 
        if (contentSize > 0) {
            animator.start();
        }
    }

The setTextContent() method is used to dynamically set the text list for switching. Considering that the content in most application scenarios is dynamically set, there is no custom attribute here to provide static settings of xml files, which can be optimized if necessary.

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mWidth = MeasureSpec.getSize(widthMeasureSpec);
 
        Rect bounds = new Rect();
        if (contentSize <= 0) {
            return;
        }
        String text = lists.get(0);
        mPaint.getTextBounds(text, 0, text.length(), bounds);
        int textHeight = bounds.height();
        Log.d("viclee", "onMeasure height is " + mHeight);
 
        paddingLeft = getPaddingLeft();
        paddingBottom = getPaddingBottom();
        paddingTop = getPaddingTop();
        mHeight = textHeight + paddingBottom + paddingTop;
 
        Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
        //Calculate text height
        float fontHeight = fontMetrics.bottom - fontMetrics.top;
        //Calculate the baseline of the text
        textBaseY = mHeight - (mHeight - fontHeight) / 2 - fontMetrics.bottom;
 
        setMeasuredDimension(mWidth, mHeight);
    }

The onMeasure() method mainly does two things: setting the height of the View according to the height of the text and the padding, and determining the baseline of the text content drawing. Please google yourself for the specific principle and calculation method of baseline.

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (contentSize <= 0) {
            return;
        }
 
        //If you directly use mHeight to control text drawing, the text cannot be displayed in the center because of the problem of text baseline
        verticalOffset = Math.round(2 * textBaseY * (0.5f - currentAnimatedValue));
        Log.d("viclee", "verticalOffset is " + verticalOffset);
        if (switchOrientation == 0) {//Scroll up Toggle
            if (verticalOffset > 0) {
                canvas.drawText(outStr, paddingLeft, verticalOffset, mPaint);
            } else {
                canvas.drawText(inStr, paddingLeft, 2 * textBaseY + verticalOffset, mPaint);
            }
        } else {
            if (verticalOffset > 0) {//Scroll down Toggle
                canvas.drawText(outStr, paddingLeft,  2 * textBaseY - verticalOffset, mPaint);
            } else {
                canvas.drawText(inStr, paddingLeft, -verticalOffset, mPaint);
            }
        }
    }

onDraw() calls the drawText() method of Canvas to draw text. According to the different rolling directions we set, the calculation methods of the drawn y coordinates are different. When you scroll up, the y value becomes smaller, and when you scroll down, the y value becomes larger. It should be noted that when calling drawText(), the x coordinate is the set left margin paddingLeft, and the Y coordinate is not the height mHeight of the control or the height textHeight of the font. It can only be the baseline of text. You can verify this yourself.

    //The callback interface is used to inform the caller of the current state of the control. The index indicates which text content to display
    public interface VerticalSwitchTextViewCbInterface {
        void showNext(int index);
        void onItemClick(int index);
    }
 
    public void setCbInterface(VerticalSwitchTextViewCbInterface cb) {
        cbInterface = cb;
    }

Finally, an interface is provided to notify the caller of the status update of View through callback (switching to new content or the current content is clicked, etc.). If you need other functions, you can expand them according to the principle of custom View.

================================

 

2016.8.16 update:

Add the gravity attribute. The gravity attribute in the horizontal direction can be set to left, right and center, indicating left alignment, right alignment and center alignment of text respectively.

Add the ellipsis attribute, which can be set to start, end and middle, respectively indicating that ellipsis will be displayed in the head, tail and middle when the text length exceeds the length of View.

Core code analysis:

private void generateEllipsisText() {
        if (ellipsisLists != null) {//Prevent double counting
            return;
        }
        ellipsisLists = new ArrayList<>();
        if (lists != null && lists.size() != 0) {
            for (String item : lists) {
                int avail = mWidth - paddingLeft - paddingRight;
                float remaining = avail - ellipsisLen;
                if (avail <= 0) {
                    ellipsisLists.add("");
                } else {
                    float itemWidth = mPaint.measureText(item, 0, item.length());
                    if (itemWidth < avail) {
                        ellipsisLists.add(item);
                    } else if (remaining <= 0) {
                        ellipsisLists.add(ellipsis);
                    } else {
                        int len = item.length();
                        float[] widths = new float[len];
                        mPaint.getTextWidths(item, 0, item.length(), widths);
                        if (mEllipsize == TextUtils.TruncateAt.END) {
                            float blockWidth = 0f;
                            for (int i = 0; i < len; i++) {
                                blockWidth += widths[i];
                                if (blockWidth > remaining) {
                                    ellipsisLists.add(item.substring(0, i) + ellipsis);
                                    break;
                                }
                            }
                        } else if (mEllipsize == TextUtils.TruncateAt.START) {
                            float blockWidth = 0f;
                            for (int i = len - 1; i >= 0; i--) {
                                blockWidth += widths[i];
                                if (blockWidth > remaining) {
                                    ellipsisLists.add(ellipsis + item.substring(i, len - 1));
                                    break;
                                }
                            }
                        } else if (mEllipsize == TextUtils.TruncateAt.MIDDLE) {
                            float blockWidth = 0f;
                            for (int i = 0, j = len - 1; i < j; i++, j--) {
                                blockWidth += (widths[i] + widths[j]);
                                if (blockWidth > remaining) {
                                    if (blockWidth - widths[j] < remaining) {
                                        ellipsisLists.add(item.substring(0, i + 1) + ellipsis + item.substring(j, len - 1));
                                    } else {
                                        ellipsisLists.add(item.substring(0, i) + ellipsis + item.substring(j, len - 1));
                                    }
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
        lists = ellipsisLists;
    }

The generateEllipsisText() method is used to process the text content. When the text exceeds the length of the View, the redundant part is marked with an ellipsis "..." Replace. ellipsisLists are used to store processed text. Available indicates the width of the area where text can be displayed, and remaining is to remove the ellipsis "..." After the width of, you can display the width of the text content. Using paint's measureText() method, you can obtain the width of the string. This width corresponds to a certain font and size. Different fonts and sizes will result in different widths. Paint's getTextWidths() method can obtain an array, which stores the width of each character. Then, according to the current ellipsize, the final text content to be displayed is determined by calculating the relationship between the character length and the View width.

        //Calculates the center position of the drawn text
        switch (alignment) {
            case TEXT_ALIGN_CENTER:
                inTextCenterX = outTextCenterX = (mWidth - paddingLeft - paddingRight) / 2 + paddingLeft;
                break;
            case TEXT_ALIGN_LEFT:
                inTextCenterX = paddingLeft + mPaint.measureText(inStr) / 2;
                outTextCenterX = paddingLeft + mPaint.measureText(outStr) / 2;
                break;
            case TEXT_ALIGN_RIGHT:
                inTextCenterX = mWidth - paddingRight - mPaint.measureText(inStr) / 2;
                outTextCenterX = mWidth - paddingRight - mPaint.measureText(outStr) / 2;
                break;
        }

The above code calculates the center position of the x-axis drawn by the text according to the current gravity. Note that due to the different length of each text, the center position of their x-axis is also different.

The renderings are as follows

 

Effects with gravity attribute and ellipsis attribute:

General effect:

example:

attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="VerticalSwitchTextView">
        <attr name="switchDuaration" format="integer"/>
        <attr name="idleDuaration" format="integer"/>
        <attr name="switchOrientation">
            <enum name="up"  value="0"/>
            <enum name="down"  value="1"/>
        </attr>
        <attr name="alignment">
            <enum name="center" value="0"/>
            <enum name="left" value="1"/>
            <enum name="right" value="2"/>
        </attr>
    </declare-styleable>
</resources>

string.xml 

<resources>
    <string name="app_name">VerticalSwitchTextView</string>
    <string name="ellipsis">\u2026</string>
</resources>

VerticalSwitchTextView.java

package com.viclee.verticalswitchtextview;

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;


public class VerticalSwitchTextView extends TextView implements View.OnClickListener {
    private static final int DEFAULT_SWITCH_DURATION = 500;
    private static final int DEFAULT_IDLE_DURATION = 2000;
    public static final int TEXT_ALIGN_CENTER = 0;
    public static final int TEXT_ALIGN_LEFT = 1;
    public static final int TEXT_ALIGN_RIGHT = 2;
    private Context mContext;

    private List<String> lists;//The displayed text content will be cycled
    private List<String> ellipsisLists;
    private int contentSize;
    private String outStr;//Text content currently slid out
    private String inStr;//Text content currently sliding in
    private float textBaseY;//baseline for text display
    private int currentIndex = 0;//Which text is currently displayed
    private String ellipsis;
    private float ellipsisLen = 0;

    private int switchDuaration = DEFAULT_SWITCH_DURATION;//Switching time
    private int idleDuaration = DEFAULT_IDLE_DURATION;//Interval time
    private int switchOrientation = 0;
    private int alignment = TEXT_ALIGN_CENTER;

    /**
     * Axis X coordinate in text
     */
    private float inTextCenterX;
    private float outTextCenterX;
    private float currentAnimatedValue = 0.0f;
    private ValueAnimator animator;

    private TextUtils.TruncateAt mEllipsize;

    private int verticalOffset = 0;
    private int mWidth;
    private int mHeight;
    private int paddingLeft = 0;
    private int paddingBottom = 0;
    private int paddingTop = 0;
    private int paddingRight = 0;

    private Paint mPaint;

    //Callback interface, which is used to inform the caller of the current state of the control
    public VerticalSwitchTextViewCbInterface cbInterface;

    public VerticalSwitchTextView(Context context) {
        this(context, null);
    }

    public VerticalSwitchTextView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public VerticalSwitchTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.VerticalSwitchTextView);
        try {
            switchDuaration = array.getInt(R.styleable.VerticalSwitchTextView_switchDuaration, DEFAULT_SWITCH_DURATION);
            idleDuaration = array.getInt(R.styleable.VerticalSwitchTextView_idleDuaration, DEFAULT_IDLE_DURATION);
            switchOrientation = array.getInt(R.styleable.VerticalSwitchTextView_switchOrientation, 0);
            alignment = array.getInt(R.styleable.VerticalSwitchTextView_alignment, TEXT_ALIGN_CENTER);
        } finally {
            array.recycle();
        }
        init();
    }

    private void init() {
        setOnClickListener(this);
        mPaint = getPaint();
        mPaint.setTextAlign(Paint.Align.CENTER);
        ellipsis = getContext().getString(R.string.ellipsis);
        ellipsisLen = mPaint.measureText(ellipsis);
        mEllipsize = getEllipsize();

        animator = ValueAnimator.ofFloat(0f, 1f).setDuration(switchDuaration);
        animator.setStartDelay(idleDuaration);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                currentAnimatedValue = (float) animation.getAnimatedValue();
                if (currentAnimatedValue < 1.0f) {
                    invalidate();
                }
            }
        });
        animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                currentIndex = (++currentIndex) % contentSize;
                if (cbInterface != null) {
                    cbInterface.showNext(currentIndex);
                }
                outStr = lists.get(currentIndex);
                inStr = lists.get((currentIndex + 1) % contentSize);

                animator.setStartDelay(idleDuaration);
                animator.start();
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
    }

    /**
     * Set the text content to be displayed circularly
     *
     * @param content Content list
     */
    public void setTextContent(List<String> content) {
        lists = content;
//        lists.clear();
//        lists = new ArrayList<>();
//        lists.add("1. Water and electricity charges for proper relaxation, Steve water and electricity charges and water and electricity charges");
//        lists.add("2. Water and electricity charges for appropriate relaxation point, Steve water and electricity charges, Steve water and electricity charges");
//        lists.add("3 properly relax");
//        lists.add("3 properly relax 1111222333");
        if (lists == null || lists.size() == 0) {
            return;
        }
        contentSize = lists.size();

        if (contentSize > 0) {
            animator.start();
        }
    }

    private void generateEllipsisText() {
        if (ellipsisLists != null) {//Prevent double counting
            return;
        }
        ellipsisLists = new ArrayList<>();
        if (lists != null && lists.size() != 0) {
            for (String item : lists) {
                int avail = mWidth - paddingLeft - paddingRight;
                float remaining = avail - ellipsisLen;
                if (avail <= 0) {
                    ellipsisLists.add("");
                } else {
                    float itemWidth = mPaint.measureText(item, 0, item.length());
                    if (itemWidth < avail) {
                        ellipsisLists.add(item);
                    } else if (remaining <= 0) {
                        ellipsisLists.add(ellipsis);
                    } else {
                        int len = item.length();
                        float[] widths = new float[len];
                        mPaint.getTextWidths(item, 0, item.length(), widths);
                        if (mEllipsize == TextUtils.TruncateAt.END) {
                            float blockWidth = 0f;
                            for (int i = 0; i < len; i++) {
                                blockWidth += widths[i];
                                if (blockWidth > remaining) {
                                    ellipsisLists.add(item.substring(0, i) + ellipsis);
                                    break;
                                }
                            }
                        } else if (mEllipsize == TextUtils.TruncateAt.START) {
                            float blockWidth = 0f;
                            for (int i = len - 1; i >= 0; i--) {
                                blockWidth += widths[i];
                                if (blockWidth > remaining) {
                                    ellipsisLists.add(ellipsis + item.substring(i, len - 1));
                                    break;
                                }
                            }
                        } else if (mEllipsize == TextUtils.TruncateAt.MIDDLE) {
                            float blockWidth = 0f;
                            for (int i = 0, j = len - 1; i < j; i++, j--) {
                                blockWidth += (widths[i] + widths[j]);
                                if (blockWidth > remaining) {
                                    if (blockWidth - widths[j] < remaining) {
                                        ellipsisLists.add(item.substring(0, i + 1) + ellipsis + item.substring(j, len - 1));
                                    } else {
                                        ellipsisLists.add(item.substring(0, i) + ellipsis + item.substring(j, len - 1));
                                    }
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
        lists = ellipsisLists;
    }

    /**
     * It is mainly used to adjust the height of TextView
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mWidth = MeasureSpec.getSize(widthMeasureSpec);

        Rect bounds = new Rect();
        if (contentSize <= 0) {
            return;
        }
        String text = lists.get(0);
        mPaint.getTextBounds(text, 0, text.length(), bounds);
        int textHeight = bounds.height();

        paddingLeft = getPaddingLeft();
        paddingRight = getPaddingRight();
        paddingBottom = getPaddingBottom();
        paddingTop = getPaddingTop();

        if (mEllipsize != null) {
            generateEllipsisText();
        }

        outStr = lists.get(0);
        if (contentSize > 1) {
            inStr = lists.get(1);
        } else {
            inStr = lists.get(0);
        }

        mHeight = textHeight + paddingBottom + paddingTop;

        Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
        //Calculate text height
        float fontHeight = fontMetrics.bottom - fontMetrics.top;
        //Calculate the baseline of the text
        textBaseY = mHeight - (mHeight - fontHeight) / 2 - fontMetrics.bottom;

        setMeasuredDimension(mWidth, mHeight);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (contentSize <= 0) {
            return;
        }
        //Calculates the center position of the drawn text
        switch (alignment) {
            case TEXT_ALIGN_CENTER:
                inTextCenterX = outTextCenterX = (mWidth - paddingLeft - paddingRight) / 2 + paddingLeft;
                break;
            case TEXT_ALIGN_LEFT:
                inTextCenterX = paddingLeft + mPaint.measureText(inStr) / 2;
                outTextCenterX = paddingLeft + mPaint.measureText(outStr) / 2;
                break;
            case TEXT_ALIGN_RIGHT:
                inTextCenterX = mWidth - paddingRight - mPaint.measureText(inStr) / 2;
                outTextCenterX = mWidth - paddingRight - mPaint.measureText(outStr) / 2;
                break;
        }

        //If you directly use mHeight to control text drawing, the text cannot be displayed in the center because of the problem of text baseline
        verticalOffset = Math.round(2 * textBaseY * (0.5f - currentAnimatedValue));
//        L.d("verticalOffset is " + verticalOffset);
        if (switchOrientation == 0) {//Scroll up Toggle
            if (verticalOffset > 0) {
                canvas.drawText(outStr, outTextCenterX, verticalOffset, mPaint);
            } else {
                canvas.drawText(inStr, inTextCenterX, 2 * textBaseY + verticalOffset, mPaint);
            }
        } else {
            if (verticalOffset > 0) {//Scroll down Toggle
                canvas.drawText(outStr, outTextCenterX, 2 * textBaseY - verticalOffset, mPaint);
            } else {
                canvas.drawText(inStr, inTextCenterX, -verticalOffset, mPaint);
            }
        }
    }

    @Override
    public void onClick(View v) {
        if (contentSize > currentIndex) {
            if (cbInterface != null) {
                cbInterface.onItemClick(currentIndex);
            }
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        mContext = null;
        if (animator != null) {
            animator.cancel();
        }
    }

    //The callback interface is used to inform the caller of the current state of the control. The index indicates which text content to display
    public interface VerticalSwitchTextViewCbInterface {
        void showNext(int index);

        void onItemClick(int index);
    }

    public void setCbInterface(VerticalSwitchTextViewCbInterface cb) {
        cbInterface = cb;
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:vswitch="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">
    <com.viclee.verticalswitchtextview.VerticalSwitchTextView
        android:id="@+id/vertical_switch_textview1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:textColor="#aa0090"
        android:textSize="30sp"
        android:padding="8dp"
        android:background="#999999"
        android:ellipsize="end"
        vswitch:alignment="left"
        vswitch:switchDuaration = "500"
        vswitch:idleDuaration = "1500"
        vswitch:switchOrientation="up"/>
    <com.viclee.verticalswitchtextview.VerticalSwitchTextView
        android:id="@+id/vertical_switch_textview2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:layout_centerInParent="true"
        android:textColor="#aa0090"
        android:textSize="30sp"
        android:padding="8dp"
        android:background="#999999"
        android:ellipsize="start"
        vswitch:alignment="center"
        vswitch:switchDuaration = "800"
        vswitch:idleDuaration = "1000"
        vswitch:switchOrientation="down"/>
</LinearLayout>

MainActivity.java

package com.viclee.verticalswitchtextview;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.WindowManager;

import java.util.ArrayList;
import java.util.Arrays;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_main);

        ArrayList<String> list = new ArrayList<String>(Arrays.asList("Able to adapt to multi text Android TextView Examples of", "The understanding is also very simple. I just list some methods I use in this library",
                "Relax properly", "Crack key", "Two ways to detect Android app Status of front and rear console switching", "Kobe"));
        VerticalSwitchTextView verticalSwitchTextView1 = (VerticalSwitchTextView) findViewById(R.id.vertical_switch_textview1);
        VerticalSwitchTextView verticalSwitchTextView2 = (VerticalSwitchTextView) findViewById(R.id.vertical_switch_textview2);
        verticalSwitchTextView1.setCbInterface(new VerticalSwitchTextView.VerticalSwitchTextViewCbInterface() {
            @Override
            public void showNext(int index) {

            }

            @Override
            public void onItemClick(int index) {
                Log.e("aaaaaaaaa", "Click" + index);
            }
        });
        verticalSwitchTextView2.setCbInterface(new VerticalSwitchTextView.VerticalSwitchTextViewCbInterface() {
            @Override
            public void showNext(int index) {

            }

            @Override
            public void onItemClick(int index) {
                Log.e("aaaaaaaaa", "Click" + index);
            }
        });
        verticalSwitchTextView1.setTextContent(list);
        verticalSwitchTextView2.setTextContent(list);
    }
}

Finished!!!

 

Tags: Android TextView

Posted by Tux-e-do on Sun, 15 May 2022 08:48:17 +0300