最近做直播项目,有个跑马灯效果,刚开始用原生的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
最后,放几张截图: