任意View的跑马灯效果


在这里示例图片的跑马灯效果,换成是其他view也是可以的。


说到跑马灯效果,最先想到的应该就是使用TextView自带的android:ellipsize="marquee"属性来实现。但是这个属性在简单易用的同时也有很大的局限性,例如由于ellipsize属性是只有当文字超出控件长度时才会生效,所以当文字较短时就无法产生跑马灯的效果。再比如不能指定滚动方向、不能指定滚动速度等。在开发中常常会遇到复杂的跑马灯需求用自带的属性无法实现的情况,之前接到一个需求要做文字的跑马灯,可是文字一共就只有4个字...那么就无法使用TextView自带的属性实现了,于是就自己实现了一个高度定制化的跑马灯View,可以实现包括图片跑马灯效果、TextView文字不超过宽度时的跑马灯效果等任意View的跑马灯效果,并且可以指定滚动的方向和速度。

主要实现方式是继承HorizontalScrollView并实现Runnable接口,通过scrollTo方法刷新界面实现。以下是MarqueeView源码:

package xyy.marqueeview;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;

/**
 * 跑马灯View
 * Created by xuyy on 2016/8/23.
 */
public class MarqueeView extends HorizontalScrollView implements Runnable{

    private Context context;
    private LinearLayout mainLayout;//跑马灯滚动部分
    private int scrollSpeed = 5;//滚动速度
    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;

    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;
    }

    @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, 50 / scrollSpeed);
    }

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

addViewInQueue()方法中先将添加的View加到滚动部分mainLayout中,再计算添加View的总宽度,便于下面计算滚动起点。

startScroll()方法中,如果方向是从左向右,那就将滚动起点设为(viewWidth, 0),如果是从右向左,那就将滚动起点设为(-screenWidth, 0)。这里要注意的是scrollTo方法参数为正时在坐标系中是负向(向左)的,参数为负时在坐标系中是正向(向右)的。

mainLayout就是滚动部分了。当mainLayout整体全部滚动出屏幕,即滚动距离=screenWidth+viewWidth时重置起点,实现循环跑马灯的效果。

mainLayout的布局很简单,就是一个横向的LinearLayout。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

</LinearLayout>

使用:

public class MainActivity extends Activity {

    private MarqueeView marqueeView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        marqueeView = (MarqueeView) findViewById(R.id.marquee_view);
        initMarqueeView();
    }

    private void initMarqueeView(){
        ImageView iv1 = new ImageView(this);
        iv1.setImageResource(R.drawable.pic1);
        marqueeView.addViewInQueue(iv1);
        ImageView iv2 = new ImageView(this);
        iv2.setImageResource(R.drawable.pic2);
        marqueeView.addViewInQueue(iv2);
        ImageView iv3 = new ImageView(this);
        iv3.setImageResource(R.drawable.pic3);
        marqueeView.addViewInQueue(iv3);
        ImageView iv4 = new ImageView(this);
        iv4.setImageResource(R.drawable.pic4);
        marqueeView.addViewInQueue(iv4);
        ImageView iv5 = new ImageView(this);
        iv5.setImageResource(R.drawable.pic5);
        marqueeView.addViewInQueue(iv5);
        ImageView iv6 = new ImageView(this);
        iv6.setImageResource(R.drawable.pic6);
        marqueeView.addViewInQueue(iv6);

        marqueeView.setScrollSpeed(8);
        marqueeView.setScrollDirection(MarqueeView.RIGHT_TO_LEFT);
        marqueeView.setViewMargin(15);
        marqueeView.startScroll();
    }
}

MainActivity布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <xyy.marqueeview.MarqueeView
        android:id="@+id/marquee_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:background="@color/black60"
        android:fillViewport="true"
        android:gravity="center"
        android:padding="5dp"/>
</RelativeLayout>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值