教你如何实现 Android TextView 文字轮播效果

效果图:

实现思路:

1.ViewAnimator 思路

使用 ViewAnimator 自身特性,对期中的子 view 实现动画切换

2.自定义 viewGroup 思路

在这个思路下,我们自定义一个容器,继承 FrameLayout ,根据数据数量自己 new 相应数量的 itemView 出来加入 FrameLayout ,动画是通过对当前 itemView 做一个出去的佛纳甘话,同时对下一个 itemView 做一个进入动画,使用 handle 实现延迟轮换

3.ViewFlipper 思路

ViewFlipper 思路和 ViewAnimator 一样,不过 ViewFlipper 使用上更灵活,这里我们根据数据流量动态往 ViewFlipper 里添加 itemView

4.自定义 textView 思路

其实这个思路也好理解,我们继承 textView ,然后在 onDraw 绘制中自己话文字,自己做动画,动画的思路是先把上一个文字上移到顶,然后再绘制下一个文字,从下面开始一直移动到中间

ViewAnimator 思路

ViewAnimator 是个 viewGroup ,可以实现动画切换其中子 view 的效果。在 xml 布局种,我们把 ViewAnimator 当一个容器,里面写轮播的 view,写多少个 view 就有多少个轮播,然后设置切换的动画,用 handle 做定时延迟轮播,调 ViewAnimator.onNext 就可以切换到下一个 view

实现思路:

1.先在 layout xml 中声明布局层级结构:

 <ViewAnimator
        android:layout_width="match_parent"
        android:layout_height="200dp">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="欢迎"/>
        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="测试"/>
        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="本程序"/>
        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="!!!!!"/>
        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="hello,world"/>
    </ViewAnimator>

2.代码种设置切换动画

viewAnimator.setOutAnimation(this, R.anim.slide_out_up);
viewAnimator.setInAnimation(this, R.anim.slide_in_down);

3.handle 延迟循环显示下一个

      public void showNext() {
        viewAnimator.showNext();
    }

    public void showPrevious() {
        viewAnimator.showPrevious();
    }

    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (autoPlayFlag) {
                showNext();
            }
            handler.sendMessageDelayed(new Message(), TIME_INTERVAL);
        }
    };

我们在需要的位置发送 handle 事件就可以了

使用 ViewAnimator 有点和确定同样明显

  • 优点:使用简单,没有难度
  • 缺点:xml 中固定了 view个数,为了兼容不同数据量,我们需要再 ViewAnimator 基础上 2 次开发

自定义 viewGroup 思路

在这个思路下,我们自定义一个容器,继承 FrameLayout ,根据数据数量自己 new 相应数量的 itemView 出来加入 FrameLayout ,动画是通过对当前 itemView 做一个出去的佛纳甘话,同时对下一个 itemView 做一个进入动画,使用 handle 实现延迟轮换

思路如下

1.在设置数据时添加相应数量的 itemView 进去

    public void setNoticeList(List<String> list) {

        // 创建TextView
        for (int i = 0; i < list.size(); i++) {
            TextView textView = createTextView(list.get(i));
            mNoticeList.add(textView);
            addView(textView);
        }
        // 显示第一条公告
        mCurrentNotice = 0;
        mNoticeList.get(mCurrentNotice).setVisibility(VISIBLE);
        // 启动轮播
        start();
    }

    private TextView createTextView(String text) {
        if (mLayoutParams == null) {
            mLayoutParams = new LayoutParams(
                    LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
            mLayoutParams.gravity = Gravity.CENTER_VERTICAL;
        }

        TextView textView = new TextView(getContext());
        textView.setLayoutParams(mLayoutParams);
        textView.setSingleLine();
        textView.setEllipsize(TextUtils.TruncateAt.END);
        textView.setTextColor(mTextColor);
        textView.setVisibility(GONE);
        textView.setText(text);
        // 如果有设置字体大小,如果字体大小为null。
        if (mTextSize > 0) {
            textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize);
        }
        return textView;
    }

2.在 handle 里面启动 itemView 切换的动画

     class NoticeRunnable implements Runnable {
        @Override
        public void run() {
            // 隐藏当前的textView
            TextView currentView = mNoticeList.get(mCurrentNotice);
            currentView.setVisibility(GONE);
            if(mExitAnimSet != null) {
                currentView.startAnimation(mExitAnimSet);
            }
            mCurrentNotice++;
            if(mCurrentNotice >= mNoticeList.size()) {
                mCurrentNotice = 0;
            }

            // 显示下一个TextView
            TextView nextView = mNoticeList.get(mCurrentNotice);
            nextView.setVisibility(VISIBLE);
            if(mEnterAnimSet != null) {
                nextView.startAnimation(mEnterAnimSet);
            }
            mHandler.postDelayed(this, mNoticeDuration);
        }
    }

    private void createEnterAnimation() {
        mEnterAnimSet = new AnimationSet(false);
        TranslateAnimation translateAnimation =
                new TranslateAnimation(0,0,0,0, TranslateAnimation.RELATIVE_TO_PARENT, 1f,
                        TranslateAnimation.RELATIVE_TO_SELF, 0f);
        AlphaAnimation alphaAnimation = new AlphaAnimation(0f,1f);
        mEnterAnimSet.addAnimation(translateAnimation);
        mEnterAnimSet.addAnimation(alphaAnimation);
        mEnterAnimSet.setDuration(DEFAULT_ANIMATION_DURATION);
    }

    private void createExitAnimation() {
        mExitAnimSet = new AnimationSet(false);
        TranslateAnimation translateAnimation =
                new TranslateAnimation(0,0,0,0, TranslateAnimation.RELATIVE_TO_SELF, 0f,
                        TranslateAnimation.RELATIVE_TO_PARENT, -1f);
        AlphaAnimation alphaAnimation = new AlphaAnimation(1f,0f);
        mExitAnimSet.addAnimation(translateAnimation);
        mExitAnimSet.addAnimation(alphaAnimation);
        mExitAnimSet.setDuration(DEFAULT_ANIMATION_DURATION);
    }

这样写最练手,但是我是不推荐这样干的,基础差一些的容易出问题,而且 google 给我们提供了一些实现,我们何必非的自己实现呢,这样写会花点时间

ViewFlipper 思路

ViewFlipper 思路像是上面 1 和 2 的结合,ViewFlipper 对动画的控制更优秀一些,我们往 ViewFlipper 里面动态添加 itemView ,基本都是这个思路,区别是使用的容器不同
这里推荐一个成熟的库:

  • TextBannerView

这个库非常完善了,也能满足大家的常用需求,是可以拿来直接用的,大家看图就明白了

思路如下

他这里自定义了一个 ViewGroup 继承自 RelativeLayout,在 view 初始化时添加了一个 ViewFlipper 进来,之后操作的都是这个 ViewFlipper 了

1.自定义 ViewGroup 初始化时添加了 ViewFlipper

    /**初始化控件*/
    private void init(Context context, AttributeSet attrs, int defStyleAttr) {

        mViewFlipper = new ViewFlipper(getContext());//new 一个ViewAnimator
        mViewFlipper.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        addView(mViewFlipper);
        startViewAnimator();
        //设置点击事件
        mViewFlipper.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = mViewFlipper.getDisplayedChild();//当前显示的子视图的索引位置
                if (mListener!=null){
                    mListener.onItemClick(mDatas.get(position),position);
                }
            }
        });

2.根据数据添加 itemView

      /**设置数据集合*/
    public void setDatas(List<String> datas){
        this.mDatas = datas;
        if (DisplayUtils.notEmpty(mDatas)){
            mViewFlipper.removeAllViews();
            for (int i = 0; i < mDatas.size(); i++) {
                TextView textView = new TextView(getContext());
                textView.setText(mDatas.get(i));
                //任意设置你的文字样式,在这里
                textView.setSingleLine(isSingleLine);
                textView.setTextColor(mTextColor);
                textView.setTextSize(mTextSize);
                textView.setGravity(mGravity);

                mViewFlipper.addView(textView,i);//添加子view,并标识子view位置
            }
        }
    }

3.添加动画

    /**
     * 设置进入动画和离开动画
     *
     * @param inAnimResId  进入动画的resID
     * @param outAnimResID 离开动画的resID
     */
    private void setInAndOutAnimation(@AnimRes int inAnimResId, @AnimRes int outAnimResID) {
        Animation inAnim = AnimationUtils.loadAnimation(getContext(), inAnimResId);
        inAnim.setDuration(animDuration);
        mViewFlipper.setInAnimation(inAnim);

        Animation outAnim = AnimationUtils.loadAnimation(getContext(), outAnimResID);
        outAnim.setDuration(animDuration);
        mViewFlipper.setOutAnimation(outAnim);
    }

之后就是用 handle 来做延迟循环,上面复制好几遍了,这里是在不想再复制了,打个源码很简单,大家直接看。

吐槽下:这个库多了一道手,多加了一个视图层级出来,其实没必要在顶层加一个 viewGroup 了,直接继承 ViewFlipper 可好

自定义 textView 思路

不继承 textView 我们直接继承 view 都可以,只要不支持 wrap_content 就好办。 核心就是在 onDraw 中实现绘制的动画。
例子这里没有使用 ValueAnimator 动画,而是 1 个 px 变化就重绘一次,性能上欠考虑。

实现思路

1.根据文字,确定文字出屏幕的零界点

// 获取文字矩阵的尺寸
Rect indexBound = new Rect();
mPaint.getTextBounds(text, 0, text.length(), indexBound);

// 文字居中绘制 Y 的坐标
my = mHeight  / 2 - (bound.top + bound.bottom) / 2

// 文字移动到最顶部
mY == 0 - bound.bottom

// 文字移动到最下部
mY = mHeight  - indexBound.top;

2.在 onDraw 中实现绘制
         // 文字首先绘制在最底部,mY 初始时 = 0
        if (mY == 0) {
            mY = getMeasuredHeight() - indexBound.top;
        }

        // 文字移动到最顶部时,更换数据,把文字移动到最底部
        if (mY == 0 - indexBound.bottom) {
            Log.i(TAG, "onDraw: " + getMeasuredHeight());
            mY = getMeasuredHeight() - indexBound.top;//返回底部
            mIndex++;//换下一组数据
        }

        // 文字移动到中间时,停止 handle 的重绘任务,延迟标准时间后再开始
        if (mY == getMeasuredHeight() / 2 - (indexBound.top + indexBound.bottom) / 2) {
            isMove = false;//停止移动
            // handle 通知标准时间后开始重绘
        }

        // 处理完 Y 坐标,开始绘制文字
        canvas.drawText(font, 0, font.length(), 10, mY, mPaintFront);

        // 最后移动 1 个 px,以实现动画效果
        mY -= 1

这里强调每移动 1个 px 就重绘一遍是为了确保动画的连贯性,但是这样系统也是 16 ms 才绘制一帧的,这样高频率的重绘并不是最优选择哦

原文地址:https://blog.51cto.com/14263171/2378053

时间: 2024-11-10 07:07:11

教你如何实现 Android TextView 文字轮播效果的相关文章

Android TextView文字空格

 表示全角空格, <string name="aaa">你好      啊</string> http://stackoverflow.com/questions/1587056/android-string-concatenate-how-to-keep-the-spaces-at-the-end-and-or-beginnin 1.Even if you use string formatting sometimes you still need white

Android TextView文字透明度和背景透明度设置

textview1.setTextColor(Color.argb(255, 0, 255, 0)); //文字透明度 控件设为半透明: 控件名.getBackground().setAlpha(int); int 在0-255之间 package net.android.alpha; import android.widget.TextView; import android.os.Bundle; import android.view.ViewGroup; import android.ap

Android无限广告轮播 - 自定义BannerView

1.概述 这其实是我第一篇想写的博客,可能是因为我遇到了太多的坑,那个时候刚入行下了很多Demo发现怎么也改不动,可能是能力有限,这次就做一个具体的实现和彻底的封装. 上次讲了Android无限广告轮播-ViewPager源码分析,有了源码分析我们对ViewPager就有了一个大概的了解,那么再来封装成自定义View,就会简单许多,附视频讲解地址:http://pan.baidu.com/s/1bpqqkGn 2.效果封装 2.1 自定义BannerViewPager extends ViewP

Android UI - 实现广告Banner轮播效果

Android UI - 实现广告Banner轮播效果 前言 本篇博客要分享的一个效果是实现广告Banner轮播效果,这个效果也比较常见,一些视频类应用就经常有,就拿360影视大全来举例吧: 用红框框住的那个效果就是小巫今天要分享的,先来思考一下会用到什么控件?有什么用户体验? 控件我们可能一下子就可以想到的自然是ViewPager,没错!用到的就是ViewPager,那么它会有什么用户体验呢,它可能有以下几个体验: 1. 间隔不停的切换图片,指示器也跟着变 2. 点击图片可以跳转到指定的页面

手把手教你用ViewPager自定义实现Banner轮播

手把手教你用ViewPager自定义实现Banner轮播 欢迎大家关注Android开源网络框架NoHttp:https://github.com/Y0LANDA/NoHttp 我们在实际开发中,很多App都会在做一个广告轮播器(可能是图片,可能是其他View),很多同学都是使用别人封装好的或者直接使用ViewPager自己来改,但是有人可能并不理解里面的原理,或者有人遇到了手势滑动冲突.我们今天就用150行代码实现一自定义的广告轮播器并不干扰原来View滑动事件. 本例代码源码及Demo传送门

Android中使用ViewPager实现屏幕页面切换和页面轮播效果

之前关于如何实现屏幕页面切换,写过一篇博文<Android中使用ViewFlipper实现屏幕切换>,相比ViewFlipper,ViewPager更适用复杂的视图切换,而且Viewpager有自己的adapter,这也让其适应复杂对象,实现数据的动态加载. ViewPager是谷歌官方给我们提供的一个兼容低版本安卓设备的软件包,里面包囊了只有在安卓3.0以上可以使用的api.而viewpager就是其中之一,利用它,我们可以做很多事情,从最简单的导航,到页面菜单等等. 下面我们就展示下Vie

自己写的文字轮播(简陋版)

最近一直在写图片的轮播图,满脑子全是图片滚动, 今天来换一个文字轮播写写. 大家不要在意样式,和内容.都是我随便写的. 主要思路就是 复制两块一样的内容,在内容滚动的过程中,判断当第二个内容滚到一定位置时,重置整体滚动的值. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <style> *{ margin: 0; padding

Android使用ViewPager实现左右循环滑动及轮播效果

ViewPager是一个常用的android组件,不过通常我们使用ViewPager的时候不能实现左右无限循环滑动,在滑到边界的时候会看到一个不能翻页的动画,可能影响用户体验.此外,某些区域性的ViewPager(例如展示广告或者公告之类的ViewPager),可能需要自动轮播的效果,即用户在不用滑动的情况下就能够看到其他页面的信息. 为此我查阅了网络上现有的一些关于实现这样效果的例子,但都不是很满意,经过反复实验,在这里总结并分享给大家,希望能有所帮助. 循环滑动效果的实现:PagerAdap

调用MyFocus库,简单实现二十几种轮播效果

一.首先点击这里下载myFocus库文件,标准文件库就行了,很小仅仅1.4M. myFocus库有以下的好处: a . 文件小巧却高效强大,能够实现二十几种轮播的效果. b . 极其简单的使用,只需要调用就可以使用,下面会介绍方法. c . 灵活的设置,很多参数可以提供设置,比如不想要文字提示,设置高度为0....更多参数适用请见网站教程页面. 二.下载下来之后,解压,看到一个文件夹,如下图所示: 对此文件夹进行一下说明:a . 打开js文件夹,然后有个js文件,就是我们最开始要调用的myfoc