Android中TextView实现垂直滚动(轮换效果,非跑马灯)

目前有这个需求,但网上找了一会儿,没发现有我的这个需求的相关文章及Demo。

没办法,自己写咯...


原理及实现代码里很详细,这里不多说了。

MainActivity:

package com.parcool.textviewverticalscroll;

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

import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TextView;

/***
 * Android垂直动画->用animation实现。 原理:每隔2秒,当前TextView做移除效果,下一个TextView做进入效果。
 * 注意:装载这个轮换TextView的LinearLayout,一定要设置一个只能显示一个TextView的高度,
 * 既->LinearLayout.height = TextView.height
 * 
 * @author parcool
 * 
 */
public class MainActivity extends Activity {
	private Animation anim_in, anim_out;
	private LinearLayout llContainer;
	private Handler mHandler;
	private boolean runFlag = true;
	private int index = 0;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		// 如果是Home键等其他操作导致销毁重建,那么判断是否存在,
		// 如果存在,那么获取上次滚动到状态的index
		// 如果不存在,那么调用初始化方法
		if (null != savedInstanceState) {
			index = savedInstanceState.getInt("currIndex");
			Log.d("tag", "The savedInstanceState.getInt value is" + index);
		} else {
			init();
		}
	}

	@SuppressLint("HandlerLeak")
	private void init() {
		// TODO Auto-generated method stub
		// 找到装载这个滚动TextView的LinearLayout
		llContainer = (LinearLayout) findViewById(R.id.ll_container);
		// 加载进入动画
		anim_in = AnimationUtils.loadAnimation(this, R.anim.anim_tv_marquee_in);
		// 加载移除动画
		anim_out = AnimationUtils.loadAnimation(this,
				R.anim.anim_tv_marquee_out);
		// 填充装文字的list
		List<String> list = new ArrayList<String>();
		for (int i = 0; i < 3; i++) {
			list.add("滚动的文字" + i);
		}
		// 根据list的大小,动态创建同样个数的TextView
		for (int i = 0; i < list.size(); i++) {
			TextView tvTemp = new TextView(this);
			LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
					LayoutParams.WRAP_CONTENT);
			lp.gravity = Gravity.CENTER;
			tvTemp.setGravity(Gravity.CENTER);
			tvTemp.setText(list.get(i));
			tvTemp.setId(i + 10000);
			llContainer.addView(tvTemp);
		}

		mHandler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				// TODO Auto-generated method stub
				super.handleMessage(msg);
				switch (msg.what) {
				case 0:
					// 移除
					TextView tvTemp = (TextView) msg.obj;
					Log.d("tag", "out->" + tvTemp.getId());
					tvTemp.startAnimation(anim_out);
					tvTemp.setVisibility(View.GONE);
					break;
				case 1:
					// 进入
					TextView tvTemp2 = (TextView) msg.obj;
					Log.d("tag", "in->" + tvTemp2.getId());
					tvTemp2.startAnimation(anim_in);
					tvTemp2.setVisibility(View.VISIBLE);
					break;
				}
			}
		};
	}

	/***
	 * 停止动画
	 */
	private void stopEffect() {
		runFlag = false;
	}

	/***
	 * 启动动画
	 */
	private void startEffect() {
		runFlag = true;
		new Thread(new Runnable() {

			@Override
			public void run() {
				// TODO Auto-generated method stub
				while (runFlag) {
					try {
						// 每隔2秒轮换一次
						Thread.sleep(2000);
						// 至于这里还有一个if(runFlag)判断是为什么?大家自己试验下就知道了
						if (runFlag) {
							// 获取第index个TextView开始移除动画
							TextView tvTemp = (TextView) llContainer
									.getChildAt(index);
							mHandler.obtainMessage(0, tvTemp).sendToTarget();
							if (index < llContainer.getChildCount()) {
								index++;
								if (index == llContainer.getChildCount()) {
									index = 0;
								}
								// index+1个动画开始进入动画
								tvTemp = (TextView) llContainer
										.getChildAt(index);
								mHandler.obtainMessage(1, tvTemp)
										.sendToTarget();
							}
						}
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						// 如果有异常,那么停止轮换。当然这种情况很难发生
						runFlag = false;
						e.printStackTrace();
					}
				}
			}
		}).start();
	}

	/***
	 * 当页面暂停,那么停止轮换
	 */
	@Override
	protected void onPause() {
		// TODO Auto-generated method stub
		super.onPause();
		stopEffect();
	}

	/***
	 * 当页面可见,开始轮换
	 */
	@Override
	protected void onResume() {
		// TODO Auto-generated method stub
		super.onResume();
		startEffect();
	}

	/***
	 * 用于保存当前index的,结合onCreate方法
	 */
	@Override
	protected void onSaveInstanceState(Bundle outState) {
		// TODO Auto-generated method stub
		super.onSaveInstanceState(outState);
		outState.putInt("currIndex", index);
	}

}

activity_main.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:id="@+id/ll_container"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context=".MainActivity" >


</LinearLayout>

anim_tv_marquee_in.xml:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_interpolator" >
    <translate
        android:duration="300"
        android:fillAfter="true"
        android:fillEnabled="true"
        android:fromYDelta="-100%"
        android:repeatCount="0"
        android:toXDelta="0" />

</set>

anim_tv_marquee_out.xml:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_interpolator" >
    <translate
        android:duration="300"
        android:fillAfter="true"
        android:fillEnabled="true"
        android:fromYDelta="0"
        android:repeatCount="0"
        android:toYDelta="100%" />

</set>

新手写博客,不容易啊,大家赞一个吧。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值