Android scroll up and down (marquee) effect realization

There is a requirement for the product to scroll up and down text. The first thing that comes to my mind is to use attribute animation to switch between two TextViews. I read a bunch of materials on the Internet and most of them are TextSwitch. It is really melancholy to write a blog without posting the renderings. I don't know the specific effect, whether there is a problem with the first switch, whether there is a problem with the last switch to the second, whether the animation is smooth, etc. I can't see anything. So according to the first idea, I found a similar approach, but it seems to be a problem, so I modified it. The renderings are as follows: (The gif frame rate is a bit low, not very smooth, and it works well on the real machine)

 

The idea is that the two TextViews use attribute animation to switch up and down, delaying the sending thread to trigger the next scroll.

code show as below:

1.ScrrollTextView.java

import android.animation.ObjectAnimator;
import android.content.Context;
import android.os.Handler;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.lanjinger.choiassociatedpress.R;

import java.util.List;

/**
 * 上下滚动的 textView
 */
public class ScrollTextView extends LinearLayout {
    private TextView mBannerTV1;
    private TextView mBannerTV2;
    private Handler handler;
    private boolean isShow = false;
    private int startY1, endY1, startY2, endY2;
    private Runnable runnable;
    private List<String> list;
    private int position = 0;
    private int offsetY = 100;
    private boolean hasPostRunnable = false;

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

    public ScrollTextView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ScrollTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        View view = LayoutInflater.from(context).inflate(R.layout.widget_scroll_text_layout, this);
        mBannerTV1 = view.findViewById(R.id.tv_banner1);
        mBannerTV2 = view.findViewById(R.id.tv_banner2);
        handler = new Handler();
        runnable = new Runnable() {
            @Override
            public void run() {
                isShow = !isShow;
                if (position == list.size() - 1) {
                    position = 0;
                }

                if (isShow) {
                    mBannerTV1.setText(list.get(position++));
                    mBannerTV2.setText(list.get(position));
                } else {
                    mBannerTV2.setText(list.get(position++));
                    mBannerTV1.setText(list.get(position));
                }

                startY1 = isShow ? 0 : offsetY;
                endY1 = isShow ? -offsetY : 0;
                ObjectAnimator.ofFloat(mBannerTV1, "translationY", startY1, endY1).setDuration(300).start();

                startY2 = isShow ? offsetY : 0;
                endY2 = isShow ? 0 : -offsetY;
                ObjectAnimator.ofFloat(mBannerTV2, "translationY", startY2, endY2).setDuration(300).start();

                handler.postDelayed(runnable, 3000);
            }
        };
    }

    public List<String> getList() {
        return list;
    }

    public void setList(List<String> list) {
        this.list = list;

        //处理最后一条数据切换到第一条数据 太快的问题
        if (list.size() > 1) {
            list.add(list.get(0));
        }
    }

    public void startScroll() {
        mBannerTV1.setText(list.get(0));
        if (list.size() > 1) {
            if(!hasPostRunnable) {
                hasPostRunnable = true;
                //处理第一次进入 第一条数据切换第二条 太快的问题
                handler.postDelayed(runnable,3000);
            }
        } else {
            //只有一条数据不进行滚动
            hasPostRunnable = false;
//            mBannerTV1.setText(list.get(0));
        }
    }

    public void stopScroll() {
        handler.removeCallbacks(runnable);
        hasPostRunnable = false;
    }


}

Points to note: 1. To turn on and off scrolling, both need to be controlled outside the control. If you need to control it yourself inside the control,

onAttachedToWindow Start the thread here, pay attention to determine whether the list is empty.

2. When the list data is greater than 1, I will manually add the first data at the back. In order to avoid, the last one is switched to one because the scroll is too fast (that is, the problem of unobvious dynamic effect), I did not judge it here. , Because there must be data passed, so Yan Jin can add a blank.


2.widget_scroll_text_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/tv_banner1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:ellipsize="end"
        android:singleLine="true"
        android:textColor="@color/skin_common_title"
        android:textSize="12sp" />

    <TextView
        android:id="@+id/tv_banner2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:ellipsize="end"
        android:singleLine="true"
        android:textColor="@color/skin_common_title"
        android:textSize="12sp" />

</RelativeLayout>

3. Specific call

        ScrollTextView marqueeText = headView.findViewById(R.id.xxxx);

        List<String> demographicsList = new ArrayList<>();

        demographicsList.add("今日测试股票 上市");
        demographicsList.add("今日科伦药业 中国人保 可申购");
        demographicsList.add("今日中国平安 上市");

        marqueeText.setList(demographicsList);
        marqueeText.startScroll();

Note: Correctly handle the life cycle problem. When to call starScroll() and stopScroll(), it depends on the specific life cycle;


tail:

I feel that you can define any animation you want in this way, and you can customize the attribute animation according to your needs. There is no need for extra new TextView(); a simple look, it seems that TextSwitch is a bit more troublesome.

After today’s task is finished, I will study TextSwitch and compare the advantages and disadvantages of the two;

 

Guess you like

Origin blog.csdn.net/android_freshman/article/details/84105637