来回滚动的背景在Android在Android 可谓是很常见了,今天自己写了一个,有参考别人的代码,修复了内存泄露问题,marqueeImage会根据view大小和背景图的大小选则是横向滚动还是竖着滚动,如果写的有什么不足或者漏洞欢迎批评指正,如果觉得写的好的话,支付宝走一波哈哈,自己写的一些view 也会继续更新 谢谢大家 嘿嘿
拷贝下面的代码和attr.xml文件到项目中就可以用了
public class MarqueeImageView extends View {
private static final String TAG = "MarqueeImageView";
//region
private Thread thread = new Thread(
new Runnable() {
@Override
public void run() {
while (start) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.sendEmptyMessage(0x123);
}
}
}
);
//endregion
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 0x123:
invalidate();//重绘
break;
}
}
};
private boolean start = true;//用来记录是否滚动
enum DirectionEnum {
left, right,up,down//方向枚举
}
enum Orientation{
horizontal, vertical//水平,垂直
}
private Bitmap background = null;
private int nowX = 0, nowY = 0;
private int backWidth, backHeight;//背景图宽,高
private int time = 40;
private int MViewHeight = 0,MViewWidth = 0;
private Orientation orientation;//方向
private int speed;//速度
private DirectionEnum direction = DirectionEnum.left;//向左
public MarqueeImageView(Context context) {
super(context);
}
public MarqueeImageView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
getAttr(attrs);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
MViewHeight = h;
MViewWidth = w;
init();
}
public void init() {
int h = background.getHeight();
int w = background.getWidth();
Log.d(TAG, "init: h" + h);
Log.d(TAG, "init: w" + w);
Log.d(TAG, "init: (float)(w/MViewWidth) " + (float)(w/MViewWidth));
//水平滚动
if ((float)(w/MViewWidth) > (float)(h/MViewHeight)){
orientation = Orientation.horizontal;
int imageW = (int) ((float) MViewHeight/ h * w);
Log.d(TAG, "init: imageW" + imageW);
background = Bitmap.createScaledBitmap(background, imageW, MViewHeight, true);
backWidth = background.getWidth();//背景宽
Log.d(TAG, "start: backWidth" + backWidth);
}
else {
orientation = Orientation.vertical;//那就垂直滚动吧
int imageH = (int) ((float)MViewWidth/w * h);
Log.d(TAG, "init: imageH " + imageH);
background = Bitmap.createScaledBitmap(background, MViewWidth, imageH, true);
backHeight = background.getHeight();//背景图宽
Log.d(TAG, "init: backHeight " + backHeight);
}
start();//调用下这个方法
}
public void start() {
start = true;
handler.sendEmptyMessage(0x123);
thread.start();
}
private void getAttr(AttributeSet attrs) {
TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.MarqueeImageView);
speed = typedArray.getInteger(R.styleable.MarqueeImageView_speed, 1);
time = typedArray.getInteger(R.styleable.MarqueeImageView_time, 40);
int resourceId = typedArray.getResourceId(R.styleable.MarqueeImageView_image, R.drawable.marquee_task);
background = BitmapFactory.decodeResource(getResources(), resourceId);
typedArray.recycle();
}
@Override
protected void onDraw(Canvas canvas) {
if (background == null) //如果背景图为空直接返回
return;
//如果是水平滚动
if (orientation == Orientation.horizontal){
if (nowX <= 0) {
nowX += speed;
direction = DirectionEnum.left;//向左移动
}
else if (nowX >= backWidth - MViewWidth - speed) {
nowX -= speed;
direction = DirectionEnum.right;//左边走到头开始向又走
}
else {
if (direction == DirectionEnum.right) {
nowX -= speed;
} else {
nowX += speed;
}
}
}
else{
if (nowY <= 0) {
nowY += speed;
direction = DirectionEnum.up;//向上
} else if (nowY >= backHeight - MViewHeight - speed) {
nowY -= speed;//减去速度
direction = DirectionEnum.down;//向下移动
} else {
if (direction == DirectionEnum.up)//如果方向是向上
nowY += speed;
else
nowY -= speed;
}
}
//当水平滚动时,nowY为0, 垂直滚动时nowX为0
Bitmap bitmap = Bitmap.createBitmap(background, nowX, nowY, MViewWidth, MViewHeight);
canvas.drawBitmap(bitmap, 0, 0, null);
Log.d(TAG, "onDraw: ");
}
//从窗口分离出来
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
Log.d(TAG, "onDetachedFromWindow: ");
start = false;//线程就不要执行了
}
}
attr.xml
MarqueeImageView 如果不指定的话默认会有一个背景图名称为 marquee_task.jpg,记得放在drawable文件夹内
如果你觉得写的好的话,支付包走一波喽,嘿嘿