Android用ViewAnimator写一个简单的控件轮播效果

Posted wodongx123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android用ViewAnimator写一个简单的控件轮播效果相关的知识,希望对你有一定的参考价值。

前言

因为项目的需求,需要实现一个文字滚动轮播的功能,图我暂时找不到,脑补一下就是文字会往上滚动,然后显示另一段文字。且有多段这样的文字需要按顺序播放的这样。

android内部自带一个ViewAnimator控件,可以实现这种控件切换的功能。

虽然本文的内容只是一个TextView的轮播功能,但是举一反三可以做到任何复杂控件的轮播

1. ViewAnimator

<ViewAnimator
    android:id="@+id/va"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="我是第一个TextView"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="我是第二个TextView"/>


</ViewAnimator>

简单设置一下ViewAnimator,这是一个ViewGroup,所以直接在内部增加子控件就可以。

而ViewAnimator的调用方式也很简单,只要调用showNext()方法,就会自动显示下一个控件。

public class MainActivity extends AppCompatActivity {

    ViewAnimator viewAnimator;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        viewAnimator = findViewById(R.id.va);
        
        viewAnimator.showNext();
    }

}

运行,显示的是 “我是第二个TextView”。

2. 动态添加View

在确认了ViewAnimator的切换功能之后,接下来就是实现一个轮播效果,假设我们有一个String类型的数组,我们需要让list内的内容一直轮播。

那我们就需要和数组大小同等数量的控件,这个无法在xml中设置,可以参考我这篇文章

Android如何在运行时动态添加View_wodongx123的博客-CSDN博客
https://blog.csdn.net/qq_41872247/article/details/114401569

总之,我们先清除ViewAnimator内部的两个TextView,然后全部采用代码添加控件的方式。

public class MainActivity extends AppCompatActivity {

    ViewAnimator viewAnimator;
    String[] list = new String[]{"我是第一个TextView", "我是第二个TextView", "我是第三个TextView", "我是第四个TextView", "我是第五个TextView",
            "我是第六个TextView", "我是第七个TextView", "我是第八个TextView", "我是第九个TextView", "我是第十个TextView"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        viewAnimator = findViewById(R.id.va);

        initView();
    }

    /**
     * 初始化ViewAnimator内部的控件
     */
    private void initView() {
        for(int i=0; i<list.length; i++){
            TextView textView = new TextView(this);
            textView.setText(list[i]);
            viewAnimator.addView(textView);
        }
    }

}

3. CountDownTimer

添加了足够数量的控件之后,就是要实现轮播的功能了,我们不用Timer这个类,因为在Android中我们不能用子线程操作UI。而Android自己用Timer+Handler封装了一个CountdownTimer类,就用他来实现定时切换的功能。

public class MainActivity extends AppCompatActivity {

    private static final long INTERVAL = 2000;
    private static final long FUTURE = INTERVAL * 2;

	......省略刚才出现过的代码......
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
		......省略上面出现过的代码......
		
        initTimer();
    }


    private void initTimer() {
    	// 构造方法两个参数,第一个参数表示多久结束timer,即间隔多久后调用onfinish,调用后timer结束。
    	// 第二个参数表示间隔多久调用一次onTick,就是间隔方法,会反复调用
        timer = new CountDownTimer(FUTURE, INTERVAL) {
            @Override
            public void onTick(long millisUntilFinished) {
                viewAnimator.showNext();
            }

            @Override
            public void onFinish() {
            	// 在结束后立刻重新启动
                timer.start();
            }

        };

        timer.start();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        timer.cancel();
        timer = null;

    }
}

4. 切换动画

最后加上切换用的动画,就简单的用补间动画就好。(在res中创建anim包,然后新建两个xml文件)

R.anim.in

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:fromYDelta="-100"
        android:toYDelta="0"
        android:duration="500"/>
</set>

R.anim.out

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:fromYDelta="0"
        android:toYDelta="100"
        android:duration="500"/>
</set>

用代码设置完,这样ViewAnimator所有的内容就结束了。

viewAnimator.setInAnimation(this, R.anim.anim_in);
viewAnimator.setOutAnimation(this, R.anim.anim_out);

5. 优化

当我们有数十甚至数百个文本需要轮播的时候,这个时候就不能创建那么多控件来进行轮流播放了,对内存的消耗太大。

我的建议是,只创建两个View,当播放第一个View的时候,更新第二个View的内容,播放第二个View的时候,更新第一个View,这样可以节约特别多的内存。

这里直接放出修改后的代码全文,都是上面出现过的代码,就更改了timer内部

public class MainActivity extends AppCompatActivity {

    private static final long INTERVAL = 2000;
    private static final long FUTURE = INTERVAL * 2;

    private int listIndex = 0;
    ViewAnimator viewAnimator;
    String[] list = new String[]{"我是第一个TextView", "我是第二个TextView", "我是第三个TextView", "我是第四个TextView", "我是第五个TextView",
            "我是第六个TextView", "我是第七个TextView", "我是第八个TextView", "我是第九个TextView", "我是第十个TextView"};

    CountDownTimer timer;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        viewAnimator = findViewById(R.id.va);

        initView();
        initTimer();
    }
    
    private void initView() {
    	// 只加载两个TextView轮流播放
        TextView textView = new TextView(this);
        textView.setText(list[0]);
        TextView textView1 = new TextView(this);
        viewAnimator.addView(textView);
        viewAnimator.addView(textView1);

        viewAnimator.setInAnimation(this, R.anim.anim_in);
        viewAnimator.setOutAnimation(this, R.anim.anim_out);
    }

    private void initTimer() {
        timer = new CountDownTimer(FUTURE, INTERVAL) {
            @Override
            public void onTick(long millisUntilFinished) {
                viewAnimator.showNext();
                // 获取下个控件
                int index = viewAnimator.getDisplayedChild();
                TextView textView = (TextView) viewAnimator.getChildAt(index > viewAnimator.getChildCount()? 0 : index);
                // 更新下个控件的内容
                textView.setText(list[listIndex++]);
                // 更新数据的下标
                if (listIndex >= list.length)
                    listIndex = 0;
            }

            @Override
            public void onFinish() {
                timer.start();
            }

        };

        timer.start();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        timer.cancel();
        timer = null;

    }
}

参考材料

实现 Android TextView 文字轮播效果 - 知乎
https://zhuanlan.zhihu.com/p/62091067
8.4.2 Android动画合集之补间动画 | 菜鸟教程
https://www.runoob.com/w3cnote/android-tutorial-alphaanimation.html

以上是关于Android用ViewAnimator写一个简单的控件轮播效果的主要内容,如果未能解决你的问题,请参考以下文章

Android用ViewAnimator写一个简单的控件轮播效果

Android控件轮播效果的延迟启动和内存泄漏

Android控件轮播效果的延迟启动和内存泄漏

Android控件轮播效果的延迟启动和内存泄漏

android 直播怎么实现的

Android ViewSwitcher 的使用