因为项目的需求,需要实现一个文字滚动轮播的功能,图我暂时找不到,脑补一下就是文字会往上滚动,然后显示另一段文字。且有多段这样的文字需要按顺序播放的这样。
Android内部自带一个ViewAnimator控件,可以实现这种控件切换的功能。
虽然本文的内容只是一个TextView的轮播功能,但是举一反三可以做到任何复杂控件的轮播
<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”。
在确认了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);
}
}
}
添加了足够数量的控件之后,就是要实现轮播的功能了,我们不用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;
}
}
最后加上切换用的动画,就简单的用补间动画就好。(在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);
当我们有数十甚至数百个文本需要轮播的时候,这个时候就不能创建那么多控件来进行轮流播放了,对内存的消耗太大。
我的建议是,只创建两个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