一个Android自定义背景视图,通过触摸绘制类星空背景图

原创 2016年08月04日 22:09:23

这个一个自定义视图,手指在视图上滑动周围的点也会跟着一起移动并连线,若手机离开,点会运动并围绕上次触摸点形成一个类圆形图案。
github地址:https://github.com/lzuntalented/BackgroundView

先上图看看效果吧
初始效果

触摸离开后效果

这个原理其实蛮简单的:
1.在屏幕上生成N个点,每个点会有x和y方向的随机增量
2.每个点也会有个值表示:若距离小于此值则两点之间绘制线段
3.将触摸点添加进N个点集合中,一同绘制,但是触摸点的最小距离大于其他点的比值距离。
4.至于最后会停留则是因为,触摸点绘制线段的时候有个靠近会加速,当一个点在靠近之后,会继续运动并逃离触摸点,但在逃离到加速度的距离时,则会倒退向触摸点靠近。

若要使用这个效果只需要应用BackgroundView这个自定义视图就行了
再贴一次代码吧


/**
 * Created by lz on 2016/7/24.
 * github地址:https://github.com/lzuntalented/BackgroundView
 * 自定义背景视图
 *
 * 参考canvas中就是绘图,地址:https://github.com/hustcc/canvas-nest.js
 */
public class BackgroundView extends View implements View.OnTouchListener,GestureDetector.OnGestureListener {

    private List<OnTouchListener> mlist = new ArrayList<>();//存储多次点击事件的响应

    private int lineCount = 99;//屏幕出现的点数量
    private Context mContext;
    private List<LineConfig> random_lines = new ArrayList<>();//屏幕出现的点集合

    private GestureDetector mGestureDetector = null;

    private LineConfig currentDown = new LineConfig();//触摸点

    private int color_point = Color.argb(100, 255, 255, 255);//点的颜色
    private int color_line = Color.argb(100,255,0,0);//线的颜色

    public BackgroundView(Context context) {
        super(context);

        mContext = context;
        init();
    }

    public BackgroundView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
        init();
    }

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

    /**
     * 初始化
     */
    private void init(){
        currentDown.max = 100000;//触摸点与其他点连线的最大距离

        /*添加手势监听*/
        mGestureDetector = new GestureDetector(mContext, this);
        this.setOnTouchListener(this);
        this.setLongClickable(true);

        WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);

        int width = wm.getDefaultDisplay().getWidth();
        int height = wm.getDefaultDisplay().getHeight();

        /*初始化点集合*/
        for(int i=0; i < lineCount ; ++i){
            LineConfig l = new LineConfig();
            l.x = (float) (Math.random() * width);
            l.y = (float) (Math.random() * height);
            l.xa = (float) (Math.random() * 2 - 1);
            l.ya = (float) (Math.random() * 2 - 1);
            l.max = 15000;

            random_lines.add(l);
        }

        /*添加触摸点到集合*/
        random_lines.add(currentDown);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);

        int canvas_width = wm.getDefaultDisplay().getWidth();
        int canvas_height = wm.getDefaultDisplay().getHeight();

        Paint paint_blue = new Paint();
        paint_blue.setStyle(Paint.Style.STROKE);
        paint_blue.setStrokeWidth(1);


        float d, x_dist, y_dist, dist;
        for(int i = 0; i < random_lines.size() ; i ++ ){
            LineConfig r = random_lines.get(i);
            r.x += r.xa;
            r.y += r.ya; //移动
            r.xa *= r.x > canvas_width || r.x < 0 ? -1 : 1;
            r.ya *= r.y > canvas_height || r.y < 0 ? -1 : 1; //碰到边界,反向反弹

            paint_blue.setColor(color_point);
            canvas.drawCircle(r.x, r.y, 1, paint_blue);

            for(int j = i + 1; j < random_lines.size() ; j ++ ){
                LineConfig e = random_lines.get(j);
                x_dist = r.x - e.x; //x轴距离
                y_dist = r.y - e.y; //y轴距离
                dist = x_dist * x_dist + y_dist * y_dist; //总距离
                if(dist < e.max){
                    if(e.touch && dist >= e.max / 2){
                        r.x -= 0.03 * x_dist;
                        r.y -= 0.03 * y_dist; //靠近的时候加速
                    }

                    paint_blue.setColor(color_line);
                    canvas.drawLine(r.x,r.y,e.x,e.y,paint_blue);
                }
            }
        }

        new DrawThread().start();//启动定时线程绘制

    }

    /**
     * 重写触摸监听事件,
     * 将添加的触摸事件添加到集合中
     * 防止外部对此视图再次添加事件导致触摸点无效
     */
    @Override
    public void setOnTouchListener(OnTouchListener l) {
        mlist.add(l);
        super.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                for (int i = 0; i < mlist.size(); ++i) {
                    OnTouchListener ml = mlist.get(i);
                    if (ml.onTouch(v, event)) {
                        return true;
                    }
                }
                return false;
            }
        });
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        mGestureDetector.onTouchEvent(event);//分发手势通知
        return false;
    }

    @Override
    public boolean onDown(MotionEvent e) {
        currentDown.touch = true;
        return false;
    }

    @Override
    public void onShowPress(MotionEvent e) {

    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        currentDown.touch = false;
        return false;
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        currentDown.x = e2.getX();//记录触摸点坐标
        currentDown.y = e2.getY();//记录触摸点坐标
        return false;
    }

    @Override
    public void onLongPress(MotionEvent e) {

    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        return false;
    }

    /**
     * 定时通知绘制线程
     * */
    private class DrawThread extends Thread{

        @Override
        public void run() {
            super.run();
            try {
                sleep(1000 / 45);//每秒绘制45次
                mHandler.sendEmptyMessage(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }

    /**绘图通知handler*/
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if(msg.what == 1) draw_canvas();
        }
    };

    /**
     * 重绘视图通知
     */
    private void draw_canvas() {
        this.invalidate();
    }

    /**
     * 屏幕点对象
     * */
    private class LineConfig{
        public float x;//x左标
        public float y;//y左标
        public float xa;//x增量
        public float ya;//y增量
        public float max;//两点间最大距离,超过此距离不再绘制线段
        public boolean touch = false;//标示是否为触摸点

    }

}

参考:https://github.com/hustcc/canvas-nest.js

相关文章推荐

Android实现炫酷的星空变幻效果

星云变幻效果

webview设置背景色

在设置项目中遇到设置webview的背景色,被搞的很头疼,直到看到这篇资料才得以解决的。http://www.2cto.com/kf/201304/205753.html 在布局文件中的webv...
  • wlz287
  • wlz287
  • 2015年09月23日 14:02
  • 263

Android GridView 选择item 放大的动画

最近有用到在GridView 中选择单个的Item 时,需要将选择的Item 放大的需求.就网上查找了一下相关资料,同时查看了一下android相关的源码. 这里记录一下,一般日后回忆和继续完善这个笔...

android 修改窗体标题的字体式样和背景图(自定义标题栏)

今天google了一下,关于android自定义窗体标题栏的问题,解决方法大概如下:    自定义一个layout,然后通过requestWindowFeature和getWindow().setFe...
  • lusonmo
  • lusonmo
  • 2011年02月18日 13:49
  • 29606

android中如何为设置了背景图的按钮自定义动画

在android开发中一般有两种方式创建带图片的按钮(Button),创建普通Button并通过android:background设置需要的背景图;或者直接创建ImageButton通过androi...

Android自定义View——可在背景图和前景图显示遮罩效果的ImageView

设置背景图或前景图的遮罩,而且遮罩范围可以设置为整张图片或非透明部分,另外,还可以设置遮罩的颜色。...

[转载]Photoshop背景图制作 : 星空幻想

利用杂色滤镜来产生不规则的点,利用云彩滤镜来营造星云。

使用 Embedded Chart 自定义图表控件和背景图

在ACE 中,Embedded Chart实际上是一个 GraphicalView对象。与一般的Chart不同,它可以嵌入到另一个Activity中(其实就是一个普通的 view),而不必通过Inte...
  • kmyhy
  • kmyhy
  • 2011年07月07日 14:17
  • 12955

自定义控件背景图加进度条

  • 2014年01月25日 09:45
  • 1.43MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:一个Android自定义背景视图,通过触摸绘制类星空背景图
举报原因:
原因补充:

(最多只允许输入30个字)