任意View的跑马灯效果
2017-02-14 21:31
316 查看
在这里示例图片的跑马灯效果,换成是其他view也是可以的。
说到跑马灯效果,最先想到的应该就是使用TextView自带的android:ellipsize="marquee"属性来实现。但是这个属性在简单易用的同时也有很大的局限性,例如由于ellipsize属性是只有当文字超出控件长度时才会生效,所以当文字较短时就无法产生跑马灯的效果。再比如不能指定滚动方向、不能指定滚动速度等。在开发中常常会遇到复杂的跑马灯需求用自带的属性无法实现的情况,之前接到一个需求要做文字的跑马灯,可是文字一共就只有4个字...那么就无法使用TextView自带的属性实现了,于是就自己实现了一个高度定制化的跑马灯View,可以实现包括图片跑马灯效果、TextView文字不超过宽度时的跑马灯效果等任意View的跑马灯效果,并且可以指定滚动的方向和速度。
主要实现方式是继承HorizontalScrollView并实现Runnable接口,通过scrollTo方法刷新界面实现。以下是MarqueeView源码:
addViewInQueue()方法中先将添加的View加到滚动部分mainLayout中,再计算添加View的总宽度,便于下面计算滚动起点。
startScroll()方法中,如果方向是从左向右,那就将滚动起点设为(viewWidth, 0),如果是从右向左,那就将滚动起点设为(-screenWidth, 0)。这里要注意的是scrollTo方法参数为正时在坐标系中是负向(向左)的,参数为负时在坐标系中是正向(向右)的。
mainLayout就是滚动部分了。当mainLayout整体全部滚动出屏幕,即滚动距离=screenWidth+viewWidth时重置起点,实现循环跑马灯的效果。
mainLayout的布局很简单,就是一个横向的LinearLayout。
使用:
MainActivity布局:
说到跑马灯效果,最先想到的应该就是使用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>
相关文章推荐
- 流媒体sos rtsp hls h264 高并发 低延时 系统 设计 录像 视频合成 转发 点播 快进 快退 单步播放 分布式集群 服务搭建
- C# 员工打卡
- Scala 异常和懒加载
- MySQL8_64位解压包安装
- python 批量下载并安装deb包
- 利用git制作内核补丁(简易版)
- 最长递增子序列(导弹拦截)
- Resource .NET 3.0.5996 资源档编辑器(.NET资源修改器)
- Android 封装RecyclerView.Adapter,省其ViewHolder
- 我是如何使用 Python 优雅的薅到网易uu的羊毛的
- 《一口气读完二战史》—— 读后总结
- codewars算法题-Sum without highest and lowest number
- bzoj1008 容斥
- 深入理解Android虚拟机三------内存分配策略
- 明明的随机数
- 总结 XSS 与 CSRF 两种跨站攻击
- 后缀表达式通过栈实现表达式树
- @@Android 稳定性研究
- codeforces 765 D Artsem and Saunders(构造)
- 蓝桥杯--算法训练 表达式计算