天天看点

Android自定义View --来回滚动背景

来回滚动的背景在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

<?xml version="1.0" encoding="utf-8"?>

<resources>

    <declare-styleable name="MarqueeImageView">

        <attr name="speed" format="integer">

        </attr>

        <!--背景图-->

        <attr name="image" format="reference"></attr>

        <attr name="time" format="integer"></attr>

    </declare-styleable>

</resources>

MarqueeImageView 如果不指定的话默认会有一个背景图名称为 marquee_task.jpg,记得放在drawable文件夹内

Android自定义View --来回滚动背景

如果你觉得写的好的话,支付包走一波喽,嘿嘿

Android自定义View --来回滚动背景