1)链接
github上地址为: https://github.com/Q42/AndroidScrollingImageView
附效果图:

2)实现源码
源码比较少,在此贴上自定义属性和代码:
<?xml version="1.0" encoding="utf-8"?><resources><declare-styleable name="ScrollingView"><attr name="src" format="reference"/><attr name="speed" format="dimension"/></declare-styleable></resources>
代码:
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import static java.lang.Math.abs;
public class ScrollingView extends View {
private static final String TAG = ScrollingView.class.getSimpleName();
private int speed;
private Bitmap bitmap;
private boolean isStarted = false;
private float offset;
private Rect clipBounds = new Rect();
public ScrollingView(Context context) {
super(context);
}
public ScrollingView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ScrollingView, 0,0);
try{
speed = typedArray.getDimensionPixelSize(R.styleable.ScrollingView_speed, 1);
bitmap = BitmapFactory.decodeResource(getResources(), typedArray.getResourceId(R.styleable.ScrollingView_src, 0));
}finally {
typedArray.recycle();
}
start();
}
public ScrollingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
protected void onDraw(Canvas canvas) {
if (canvas == null) {
return;
}
//拿到画布的大小
canvas.getClipBounds(clipBounds);
//获取src的图片宽度
float layerWidth = bitmap.getWidth();
//后面如果开启了滚动动画,那么将会不断减少位移,这里判断如果减少的位移已经不少于src图片宽度时,则让其复位,不然在下面的循环中将会重复绘制多遍影响性能
//源码中的写的较复杂,不理解,这里我直接改成了复位为0
if (offset < -layerWidth) {
// offset += (floor(abs(offset) / layerWidth) * layerWidth);
offset = 0;
}
//使用一个变量接收一下位移量
float left = offset;
//如果left不大于画布的宽度,则循环绘制
while (left < clipBounds.width()) {
//前提说明:
//通过drawBitmap进行绘制,这里的核心是通过控制左边的起始绘制坐标来达成图片的滚动效果
//left为负数时,起始点将在绘制原点偏左,但是控件显示区域不变,这样将会使得图片的左边一块区域不会显示,右边空一块(附图)
//left为正数时,起始点将在绘制原点偏右,但是控件显示区域不变,这样将会使得图片的右边一块区域不会显示,左边空一块
//所以通过控制left参数,就可以达成拼接图片的目的!就相当于把图片从中间某一个地方剪开,把左边的图片
//原理:将left坐标通过speed速度进行变化不断偏移,然后基于left进行绘制,此处while循环和left+=layoutWidth是为了画布中不出现空白断节的目的,如果改成if的话,当left偏移足够多时,就没法接头造成显示空白断截的情况
//其中,关于方向的控制,设置为speed为正时,滚动方向为从右到左;
// 为负数时,滚动方向从左到右
//具体控制手段为:为正时,getBitmapLeft方法不作处理,left将会与偏移量offset一致越负越多,导致左边的绘制坐标从开始不断向左,图片会从左向右绘制直到把右边画布填满,达到图片在从右向左滚的效果
//为正数时,getBitmapLeft方法对left进行处理,为了使方向相反,需要使绘制坐标从开始不断向右,所以返回的是clipBounds.width() +(- layerWidth) - left;
//图片会从右向左绘制直到把左边填充满,之所以需要-layoutWidth,是因为如果画布宽度是图片宽度的几倍时,没有减去的话最左边的一个图片宽度将会出现空白出现断层(left将不能从最左边开始画)
canvas.drawBitmap(bitmap, getBitmapLeft(layerWidth, left), 0, null);
left += layerWidth;
//PS:left是接收的offset值,该值在下面的代码中是一直递减的(offset -= abs(speed);)
}
if (isStarted) {
offset -= abs(speed);
//通过speed修改偏移量重绘
postInvalidateOnAnimation();
}
}
/**
* 用于设置drawBitmap时左边的坐标,控制滚动的方向,
* 当速度为正数时,将left坐标原样返回,滚动方向为从右到左(返回的left的变化趋势将会从0一直减少到-layoutWidth)
* 当速度为负数时,则取全left剩余的部分,滚动方向从左到右(返回的数的变化趋势将会从clipBounds.width() - layerWidth增加到clipBounds.width())
* @param layerWidth bitmap图片的宽度
* @param left 当前的left坐标,即记录的offset位移量
* @return
*/
private float getBitmapLeft(float layerWidth, float left) {
if (speed < 0) {
return clipBounds.width() - layerWidth - left;
} else {
return left;
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), bitmap.getHeight());
}
/**
* Start the animation
*/
public void start() {
if (!isStarted) {
isStarted = true;
postInvalidateOnAnimation();
}
}
/**
* Stop the animation
*/
public void stop() {
if (isStarted) {
isStarted = false;
invalidate();
}
}
public boolean isStarted(){
return isStarted;
}
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/a6511631/article/details/47703879