竖向:
public class LoopScrollView extends View {
private final int speed;
private final Bitmap bitmap;
private Rect clipBounds = new Rect();
private float offset = 0;
private boolean isStarted;
public LoopScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ParallaxView, 0, 0);
try {
speed = ta.getDimensionPixelSize(R.styleable.ParallaxView_speed, 10);
bitmap = BitmapFactory.decodeResource(getResources(), ta.getResourceId(R.styleable.ParallaxView_src, 0));
} finally {
ta.recycle();
}
// start();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(bitmap.getWidth(), MeasureSpec.getSize(heightMeasureSpec));
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (canvas == null) {
return;
}
canvas.getClipBounds(clipBounds);
float normalizedOffset = offset;
float layerHeight = bitmap.getHeight();
if (offset <= -layerHeight) {
offset += (floor(abs(normalizedOffset) / layerHeight) * layerHeight);
}
float top = offset;
while (top < clipBounds.height()) {
canvas.drawBitmap(bitmap, 0, getBitmapTop(layerHeight, top), null);
top += layerHeight;
}
if (isStarted) {
offset -= speed;
postInvalidateOnAnimation();
}
}
private float getBitmapTop(float layerHeight, float top) {
float bitmapTop = top;
if (speed < 0) {
bitmapTop = clipBounds.height() - layerHeight - top;
}
return bitmapTop;
}
/**
* Start the animation
*/
public void start() {
if (!isStarted) {
isStarted = true;
postInvalidateOnAnimation();
}
}
/**
* Stop the animation
*/
public void stop() {
if (isStarted) {
isStarted = false;
invalidate();
}
}
}
横向:
public class LoopScrollView extends View {
private final int speed;
private final Bitmap bitmap;
private Rect clipBounds = new Rect();
private int offset = 0;
private boolean isStarted;
public LoopScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ParallaxView, 0, 0);
try {
speed = ta.getDimensionPixelSize(R.styleable.ParallaxView_speed, 10);
bitmap = BitmapFactory.decodeResource(getResources(), ta.getResourceId(R.styleable.ParallaxView_src, 0));
} finally {
ta.recycle();
}
start();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), bitmap.getHeight());
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (canvas == null) {
return;
}
canvas.getClipBounds(clipBounds);
int normalizedOffset = offset;
int layerWidth = bitmap.getWidth();
if (offset < -layerWidth) {
offset += (int) (floor(abs(normalizedOffset) / (float) layerWidth) * layerWidth);
}
int left = offset;
while (left < clipBounds.width()) {
canvas.drawBitmap(bitmap, getBitmapLeft(layerWidth, left), 0, null);
left += layerWidth;
}
if (isStarted) {
offset -= speed;
postInvalidateOnAnimation();
}
}
private float getBitmapLeft(int layerWidth, int left) {
float bitmapLeft = left;
if (speed < 0) {
bitmapLeft = clipBounds.width() - layerWidth - left;
}
return bitmapLeft;
}
/**
* Start the animation
*/
public void start() {
if (!isStarted) {
isStarted = true;
postInvalidateOnAnimation();
}
}
/**
* Stop the animation
*/
public void stop() {
if (isStarted) {
isStarted = false;
invalidate();
}
}
}
从左滚动到右再从右滚动到左:
public class LoopScrollView extends View {
private final int speed;
private final Bitmap bitmap;
private Rect clipBounds = new Rect();
private float offset = 0;
private boolean isStarted;
private boolean leftToRight = true;
public LoopScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ParallaxView, 0, 0);
try {
speed = ta.getDimensionPixelSize(R.styleable.ParallaxView_speed, 10);
bitmap = BitmapFactory.decodeResource(getResources(), ta.getResourceId(R.styleable.ParallaxView_src, 0));
} finally {
ta.recycle();
}
// start();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), bitmap.getHeight());
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (canvas == null) {
return;
}
canvas.getClipBounds(clipBounds);
float layerWidth = bitmap.getWidth();
if (offset <= -layerWidth+ ScreenUtils.getScreenWidth(getContext())) {
leftToRight = false;
offset += abs(speed);
// offset += (floor(abs(offset) / layerWidth) * layerWidth);
} else if (offset >= 0) {
leftToRight = true;
}
float left = offset;
while (left < clipBounds.width()) {
canvas.drawBitmap(bitmap, getBitmapLeft(layerWidth, left), 0, null);
left += layerWidth;
}
if (isStarted) {
if (leftToRight) {
offset -= abs(speed);
} else {
offset += abs(speed);
}
postInvalidateOnAnimation();
}
}
private float getBitmapLeft(float layerWidth, float left) {
if (speed < 0) {
return clipBounds.width() - layerWidth - left;
} else {
return left;
}
}
/**
* Start the animation
*/
public void start() {
if (!isStarted) {
isStarted = true;
postInvalidateOnAnimation();
}
}
/**
* Stop the animation
*/
public void stop() {
if (isStarted) {
isStarted = false;
invalidate();
}
}
}
注意以上代码需要:
自定义属性:
在values文件甲中的attrs.xml中加上
<declare-styleable name="ParallaxView">
<attr name="speed" format="dimension" />
<attr name="src" format="reference" />
</declare-styleable>
使用方法:
在activity 或者fragment中
@Override
public void onResume() {
super.onResume();
调用LoopScrollView的start
}
@Override
protected void onPause() {
super.onPause();
调用LoopScrollView的stop
}