Android跑马灯特效之动态实现多个文本同时一起滚动

       最近做直播项目,有个跑马灯效果,刚开始用原生的TextView实现,给产品一看,果断被否定了,于是自定义了一个MarqueeTextView可以自动获得焦点,加入足够多的文字的自己就跑动起来了,于是又拿给产品,说是有五个广告文本同时一起跑动,由于UI请假,只能自行脑补设计效果,然后自定义了一个MarqueeView往上面添加一个view,里面包含5个文本,一直找产品确认是不是最多只有5个文,产品也确认过是5个,于是请求数据成功后,把里面的内容设置到文本里面,但是运行一段时间后发现一个问题,5个文本的文字过多时同时一起跑,跑到3个就消失了,这很显然和需求不符,第2天后台添加了一个数据,这样的话之前固定写死5个文本的方法肯定不行,于是改为使用横向的HorisontalScrollView+recycleview,在线程里面开启位移动画这样也可以实现跑马灯效果,然后请求到数据后,直接往recycleview里面适配就好了,这样使用也出现了一个很奇怪的大bug,HorisontalScrollView+LinearLayout+recycleview在Android7.0及以上系统上最多只显示3个数据,于是改为RelativeLayout,这时界面正常显示,在Activity或Fragment结束时记得清除动画避免内存泄漏。希望小伙伴们接到需求要认真思考,确定后再开始写代码,要不然做很多无用功,来回折腾浪费时间,当然有些不确定的需求也没办法,只有我们自己尽量思考全面,做更多准备。

1.使用自定义MarqueeTextView实现跑马灯效果,代码如下:

/**
 * 作者: njb
 * 时间: 2018/12/13 14:55
 * 描述:
 * 来源:
 */
public class MarqueeTextView extends android.support.v7.widget.AppCompatTextView {
    public MarqueeTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public MarqueeTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MarqueeTextView(Context context) {
        super(context);
    }

    @Override

    public boolean isFocused() {
        return true;
    }
}

布局文件代码:




    
2.使用自定义的MarqueeView实现跑马灯效果,代码如下:
/**
 * 作者: njb
 * 时间: 2018/12/13 14:55
 * 描述:
 * 来源:
 */
public class MarqueeView extends HorizontalScrollView implements Runnable {
    private Context context;
    private LinearLayout mainLayout;//跑马灯滚动部分
    private int scrollSpeed = 10;//滚动速度
    private int scrollDirection = LEFT_TO_RIGHT;//滚动方向
    private int currentX;//当前x坐标
    private int viewMargin = 20;//View间距
    private int viewWidth;//View总宽度
    private int screenWidth;//屏幕宽度

    public static final int LEFT_TO_RIGHT = 1;
    public static final int RIGHT_TO_LEFT = 2;
    private int scrollDuration = 3000;

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

    public MarqueeView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MarqueeView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.context = context;
        initView();
    }

    void initView() {
        WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        screenWidth = wm.getDefaultDisplay().getWidth();
        mainLayout = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.scroll_content, null);
        this.addView(mainLayout);
    }

    public void addViewInQueue(View view){
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
                LinearLayout.LayoutParams.WRAP_CONTENT);
        lp.setMargins(viewMargin, 0, 0, 0);
        view.setLayoutParams(lp);
        mainLayout.addView(view);
        view.measure(0, 0);//测量view
        viewWidth = viewWidth + view.getMeasuredWidth() + viewMargin;
    }

    //开始滚动
    public void startScroll(){
        removeCallbacks(this);
        currentX = (scrollDirection == LEFT_TO_RIGHT ? viewWidth : -screenWidth);
        post(this);
    }

    //停止滚动
    public void stopScroll(){
        removeCallbacks(this);
    }

    //设置View间距
    public void setViewMargin(int viewMargin){
        this.viewMargin = viewMargin;
    }

    //设置滚动速度
    public void setScrollSpeed(int scrollSpeed){
        this.scrollSpeed = scrollSpeed;
    }

    //设置滚动方向 默认从左向右
    public void setScrollDirection(int scrollDirection){
        this.scrollDirection = scrollDirection;
    }

    //设置滚动间隔时间
    public void setDuration(int scrollDuration){
        this.scrollDuration  = scrollDuration;
        Log.d("scrollDuration",scrollDuration+"");
    }

    @Override
    public void run() {
        switch (scrollDirection){
            case LEFT_TO_RIGHT:
                mainLayout.scrollTo(currentX, 0);
                currentX --;

                if (-currentX >= screenWidth) {
                    mainLayout.scrollTo(viewWidth, 0);
                    currentX = viewWidth;
                }
                break;
            case RIGHT_TO_LEFT:
                mainLayout.scrollTo(currentX, 0);
                currentX ++;

                if (currentX >= viewWidth) {
                    mainLayout.scrollTo(-screenWidth, 0);
                    currentX = -screenWidth;
                }
                break;
            default:
                break;
        }
        postDelayed(this, 100 / scrollSpeed);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return false;
    }
}

布局文件代码如下:

    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:background="#222222">

   

3.使用HorizontalScrollView+Recycleview实现跑马灯效果,代码如下:

package com.example.administrator.timertask;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.TranslateAnimation;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;

import com.example.administrator.timertask.adapter.MarqueeAdapter;
import com.example.administrator.timertask.bean.ProfitBean;

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

public class HorizontalScrollViewActivity extends AppCompatActivity {
    private HorizontalScrollView mNoticeScrollView;
    private TranslateAnimation mRigthToLeftAnim;
    private final static float SCOLL_V = 0.2f;
    private RelativeLayout ll_marquee;
    private MarqueeAdapter marqueeAdapter;
    private List mList;
    private RecyclerView recyclerView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_horizontalscrollview);
        initView();
        initAdapter();
    }

    private void initAdapter() {
        mList = new ArrayList<>();
        for(int i=0;i<8;i++){
            ProfitBean profitBean = new ProfitBean();
            profitBean.setName("恭喜张昊天战队爱尚值收益222222.88元");
            mList.add(profitBean);
        }
        marqueeAdapter = new MarqueeAdapter(this,mList);
        recyclerView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,false));
        recyclerView.setAdapter(marqueeAdapter);
    }

    private void initView() {
        ll_marquee = findViewById(R.id.ll_marquee);

        mNoticeScrollView = (HorizontalScrollView) findViewById(R.id.horiSv);
         recyclerView = findViewById(R.id.rv_marquee);


        recyclerView.post(new Runnable() {
            @Override
            public void run() {
                mRigthToLeftAnim = new TranslateAnimation(mNoticeScrollView.getWidth(), -recyclerView.getWidth(), 0, 0);
                mRigthToLeftAnim.setRepeatCount(Animation.INFINITE);
                mRigthToLeftAnim.setInterpolator(new LinearInterpolator());
                mRigthToLeftAnim.setDuration((long) ((mNoticeScrollView.getWidth() + recyclerView.getWidth()) / SCOLL_V));
                recyclerView.startAnimation(mRigthToLeftAnim);
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        recyclerView.clearAnimation();
    }
}

MarqueeAdapter代码:

package com.example.administrator.timertask.adapter;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.example.administrator.timertask.R;
import com.example.administrator.timertask.bean.ProfitBean;

import java.util.List;

public class MarqueeAdapter extends RecyclerView.Adapter {
    private Context mContext;
    private List mDatas;

    public MarqueeAdapter(Context mContext, List mDatas) {
        this.mContext = mContext;
        this.mDatas = mDatas;
    }


    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(mContext).inflate(R.layout.item_marquee,parent, false);
        ViewHolder myViewHolder = new ViewHolder(view);
        return myViewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        holder.itemView.setTag(position);
        ProfitBean profitBean = mDatas.get(position);
        holder.textView.setText(profitBean.getName());
    }

    @Override
    public int getItemCount() {
        return mDatas.size();
    }

    static class ViewHolder extends RecyclerView.ViewHolder{
        TextView textView;

        ViewHolder(View view) {
            super(view);
            textView = view.findViewById(R.id.tv_profit);
        }
    }
}

实体类:

package com.example.administrator.timertask.bean;

public class ProfitBean {
    private String name;
    private String price;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPrice() {
        return price;
    }

    public void setPrice(String price) {
        this.price = price;
    }
}

布局文件代码:activity_horizontalscrollview




    

        

            
        
    


最后,放几张截图:

Android跑马灯特效之动态实现多个文本同时一起滚动_第1张图片

Android跑马灯特效之动态实现多个文本同时一起滚动_第2张图片

 Android跑马灯特效之动态实现多个文本同时一起滚动_第3张图片

 

你可能感兴趣的:(开发实例)