安卓自定义弹幕view,实现飞屏

前两天在电脑上使用迅雷的时候发现,现在的迅雷有一个类似弹幕的东西,热门搜索词会循环的在屏幕上飞过,就想能不能做一个安卓的飞屏view,然后在一番尝试后做出来了一个比较像样的demo.然后由于技术有限也没有做深入研究.现在贴上来.

代码思路:
1.整个view是继承relativelayout的ViewGroup,然后飞过的每个”小蜜蜂”是一个textview.
2.ViewGroup需要根据设定的宽高值及飞屏的行数来确定自己的宽高
(当高度为fill_parent 或者 固定值时,如果设置的高度小于要显示的行数*行高,设置间隔高度等于行高,其实这是设置的固定值并不生效)
3.自定义MyTextView继承textView,并添加字段,point来标志自身的位置,speed表示每次更新位置时的增幅,相当于移动速度
4.在ViewGroup中维护两个list,一个表示等待显示的view的集合,一个表示正在显示的view的集合,当需要添加view到ViewGroup时,取waitList中第一个view加入ViewGroup中,然后不断更新正在显示的view的位置信息即可

表达的比较混乱,表达能力不好,但是程序员交流直接看代码就好.上面仅供参考.

FlyingStringLayout代码

package com.example.flyingstring;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.AvoidXfermode.Mode;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;

public class FlyingStringLayout extends RelativeLayout {

    private Context mContext;
    /**
     * 文字的行数(默认3)
     */
    private int mStrLineNum = 5;

    /**
     * 间隔的行数=文字行数 + 1
     */
    private int mSeparatorLineNum = mStrLineNum + 1;

    /**
     * 每行文字的高度
     */
    private int mStrLineHeight;

    /**
     * 间隔的高度
     */
    private int mSeparatorHeight;

    /**
     * 字体大小(sp)
     */
    private int mTextSize = 20;
    /**
     * 画笔
     */
    private Paint paint;

    private int[] colors = { Color.parseColor("#bb45C9C2"), Color.parseColor("#bb2727E7"), Color.parseColor("#bbEDF21C"), Color.parseColor("#bb8C1AF4"), Color.parseColor("#bb65A967"), Color.parseColor("#bb32DC98"), Color.parseColor("#bbE72753"), Color.parseColor("#bb2E52E0"), Color.parseColor("#bb73CC42") };
    private String[] strs = { "bigger", "哈尔的移动城堡", "龙猫", "千与千寻", "X战警", "火影忍者", "海贼王", "英雄联盟", "死神", "死亡来临前的一小时", "地球毁灭", "外星来客", "荆棘之兴", "攻速加成", "绿萝", "太阳花", "我的野蛮女友", "安卓开发", "玻璃栈道" };//

    /**
     * 用于存储将要显示的子view
     */
    private List waitingList = new ArrayList<>();
    /**
     * 用于存储正在显示的子view
     */
    private List showingList = new ArrayList<>();
    /**
     * 用于记录每一行的y轴的位置
     */
    private List mLinePoints = new ArrayList<>();// 记录每一行的高度位置

    private long lastTime, currentTime;// 记录显示时间
    /**
     * 用于标记两个子view显示之间的时间差(毫秒值)
     */
    private long interval = 1000;
    /**
     * 用于记录上一个view显示所在行
     */
    private int showAtLastLine = mStrLineNum - 1;
    /**
     * 记录被点击了的子view
     */
    private FlyTextView mClickView;
    private OnItemClickListener mItemClickListener;

    public OnItemClickListener getOnItemClickListener() {
        return mItemClickListener;
    }

    public void setOnItemClickListener(OnItemClickListener mItemClickListener) {
        this.mItemClickListener = mItemClickListener;
    }

    public FlyingStringLayout(Context context) {
        this(context, null);
    }

    public FlyingStringLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public FlyingStringLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mContext = context;
        init();
    }

    private void init() {
        // 初始化画笔
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setTextSize(TransUtil.sp2px(mContext, mTextSize));

        Rect rect = new Rect();
        String str = "例子";
        paint.getTextBounds(str, 0, str.length() - 1, rect);
        mStrLineHeight = rect.height();

        Random random = new Random();

        for (int i = 0; i < strs.length; i++) {
            FlyTextView textView = new FlyTextView(mContext);
            LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
            textView.setLayoutParams(params);
            String string = strs[i];

            // 设置TextView显示样式
            initTextView(random, textView, string);

            waitingList.add(textView);
        }
    }



    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width, height;

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);

        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        if (widthMode != MeasureSpec.EXACTLY) {
            width = 600;
        } else {
            width = widthSize;
        }

        mLinePoints.clear();
        // 确定控件的宽高及行间隔
        if (heightMode != MeasureSpec.EXACTLY) {
            mSeparatorHeight = mStrLineHeight;
            height = mStrLineHeight * (mStrLineNum + mSeparatorLineNum);
            for (int i = 0; i < mStrLineNum; i++) {
                mLinePoints.add((i + 1) * 2 * mStrLineHeight);
            }
        } else {
            if (heightSize <= mStrLineHeight * mStrLineNum) {
                mSeparatorHeight = mStrLineHeight;
                height = mStrLineHeight * (mStrLineNum + mSeparatorLineNum);
                for (int i = 0; i < mStrLineNum; i++) {
                    mLinePoints.add((i + 1) * 2 * mStrLineHeight);
                }
            } else {
                mSeparatorHeight = (heightSize - mStrLineHeight * mStrLineNum) / mSeparatorLineNum;
                for (int i = 0; i < mStrLineNum; i++) {
                    mLinePoints.add((i + 1) * (mSeparatorHeight + mStrLineHeight));
                }
                height = heightSize;

            }
        }
        setMeasuredDimension(width, height);
    }

    @SuppressLint("DrawAllocation")
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        currentTime = System.currentTimeMillis();
        //每间隔1秒出现一个新的
        if (currentTime - lastTime > interval && waitingList.size() > 0) {
            lastTime = currentTime;
            FlyTextView textView = waitingList.get(0);
            waitingList.remove(0);

            //设置每一个将要显示的view的所在行,按顺序依次显示
            if (showAtLastLine == mStrLineNum - 1) {
                showAtLastLine = 0;
            } else {
                showAtLastLine++;
            }
            textView.setPoint(new Point(getMeasuredWidth(), mLinePoints.get(showAtLastLine)));
            showingList.add(textView);
            addView(textView);
        }

        //依次为每一个子view定位最新位置并更新下一次要显示的位置
        for (int i = 0; i < getChildCount(); i++) {
            FlyTextView ftv = showingList.get(i);
            ftv.layout(ftv.getPoint().x, ftv.getPoint().y - ftv.getHeight(), ftv.getPoint().x + ftv.getWidth(), ftv.getPoint().y);
            if (ftv != mClickView) {
                ftv.refresh();
            }
        }

        //将已经飘出屏幕的子view移除并添加到waitingList中待下一轮显示
        Iterator it = showingList.iterator();
        while (it.hasNext()) {
            FlyTextView ftv = it.next();
            if (ftv.getPoint().x <= -ftv.getWidth()) {
                it.remove();
                waitingList.add(ftv);
                removeView(ftv);
            }
        }
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        requestLayout();
    }

    /**
     * 条目点击的接口
     *
     */
    interface OnItemClickListener {
        void onClick(String text);
    }


    /**
     * 对子view进行设置
     * 
     * @param random
     * @param textView
     * @param string
     */
    private void initTextView(Random random, FlyTextView textView, String string) {
        textView.setTextSize(mTextSize);
        textView.setText(string);
        textView.setBackgroundColor(colors[random.nextInt(9)]);
        textView.setTextColor(Color.WHITE);
        textView.setPadding(10, 0, 10, 0);
        textView.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                if (v == mClickView) {
                    mClickView = null;
                    return;
                }
                mClickView = (FlyTextView) v;
                if (mItemClickListener != null) {
                    mItemClickListener.onClick(mClickView.getText().toString());
                }
            }
        });
    }
}

中间”小蜜蜂”的类

package com.example.flyingstring;

import java.util.Random;

import android.content.Context;
import android.graphics.Point;
import android.widget.TextView;

public class FlyTextView extends TextView {

    private int speed;// 移动速度
    private Point point;// 标记坐下角位置

    public FlyTextView(Context context) {
        super(context);
        speed = new Random().nextInt(5) + 5;
    }

    public int getSpeed() {
        return speed;
    }

    public void setSpeed(int speed) {
        this.speed = speed;
    }

    public Point getPoint() {
        return point;
    }

    public void setPoint(Point point) {
        this.point = point;
    }

    public void refresh() {
        point.x -= speed;
    }

}

源码点击下载

你可能感兴趣的:(Android)