Android开发(28) 绘制无限加载的温度曲线

需求

实现一个温度变化曲线
该曲线的数据时不断加载的,如下图。
支持手势,当不断向左拖动时,图形曲线要随着拖动移动,并在拖动到边界时需要加载更多数据。

步骤:

1.在Activity里放一个surfaceView

2.为surfaceView 添加监听器

            surfaceHolder = surfaceView1.getHolder();
    mMySurfaceCallback = new MySurfaceCallback();
    surfaceHolder.addCallback(mMySurfaceCallback);

3.实现监听器。

    class MySurfaceCallback implements android.view.SurfaceHolder.Callback {
    MyDraw mMyDraw;

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        mMyDraw.onSurfaceChanged();
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        mMyDraw = new MyDraw();
        mMyDraw.draw();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {

    }

}

4.编写绘制图形的方法

    class MyDraw {
            Paint p;
            Canvas canvas;
    
            int unit_x = 80; // 单位 宽度,根据要 绘制的个数不同而计算
            int unit_y = 10;// 单位高度 ,固定
    
            final int preInit_x = 50;// 开始位置
            final int preInit_y = 550;// 最大的Y顶点。
    
            Point origin;
    
            final int MAX_Fliing_X = unit_x * 20;// 最大20个
    
            public MyDraw() {
                super();
                p = new Paint(); // 创建画笔
    
                origin = new Point(preInit_x, preInit_y);// 坐标系的原点
            }
    
            /**
             * 拖动的范围,x > 0说明是 从左到右拖动。 x<0是从右向左拖动
             * 
             * @param x_changed
             */
            public void onFliing(float x_changed) {
                float newX = origin.x + x_changed;
                if (newX > preInit_x)
                    newX = preInit_x;
                int minNewX = -((result.length) * unit_x - surfaceView1.getWidth());
                boolean isToEnd = false;// 是否到达了最后一个点。即拖到最右侧极限处。
                if (newX < minNewX) {
                    newX = minNewX;
                    isToEnd = true;
                }
                int x = (int) newX;
                if (x == origin.x)
                    return;
                origin = new Point(x, origin.y);//更改坐标系原点的位置
                draw();
    
                if (isToEnd) {// 触发 到达顶点的方法。
                    raiseScrollToEnd();
                }
            }
    
            public void draw() {
                canvas = surfaceHolder.lockCanvas();
                onDdraw(canvas);
                surfaceHolder.unlockCanvasAndPost(canvas);
            }
    
            public void onDdraw(Canvas c) {
                Log.i("PDWY", String.format("新原点位置 :(%s, %s)", origin.x, origin.y));
    
                Rect r;
    
                int height = c.getHeight();
                int width = c.getWidth();
    
                c.drawColor(Color.BLACK);
    
                p.setColor(Color.RED);
                p.setStrokeWidth(2);
                p.setStyle(Paint.Style.STROKE);
                r = new Rect(2, 2, width - 2, height - 2);
                c.drawRect(r, p);
    
                p.reset();
                p.setColor(Color.RED);
                p.setStrokeWidth(5);
    
                float[] lines = new float[max_unit];
                lines = evalPosition(result, unit_x, unit_y, origin);
                // lines = new float[]{0,0,50,500,100,400,100,400,150,500,0,0};
                // drawLines方法用一组float表示要绘制的直线,每个直线用4个点表示,前两个为起端点,后两个为终端点
                c.drawLines(lines, 2, lines.length - 2, p);
                p.reset();
                p.setColor(Color.parseColor("#dcdcdc"));
                drawEndPoint(lines, 2, lines.length - 2, p, c);
            }
    
            private void drawEndPoint(float[] lines, int offset, int count,
                    Paint p2, Canvas c) {
                for (int i = offset; i < count; i += 2) {
                    float x = lines[i];
                    float y = lines[i + 1];
                    c.drawCircle(x, y, 8, p2);
                }
            }
    
            private float[] evalPosition(float[] result2, int unit_widht,
                    int unit_height, Point origin) {
                if (result2 == null)
                    return new float[0];
                float[] val = new float[result2.length * 4];
    
                for (int i = 0; i < result2.length; i++) {
                    float y = origin.y - result2[i] * unit_height;
                    float x = origin.x + unit_widht * i;
    
                    val[i * 4 + 0] = x;
                    val[i * 4 + 1] = y;
                    val[i * 4 + 2] = x;
                    val[i * 4 + 3] = y;
                }
                return val;
            }
    
            final int max_unit = 6;
    
            public void onSurfaceChanged() {
    
            }
        }
  1. 注册 手势 ,当手指拖动时,曲线要随着变化。

     surfaceView1.setOnTouchListener(new OnTouchListener() {
             int state = 0;
             float x_start;
    
             @Override
             public boolean onTouch(View v, MotionEvent event) {
                 // mGestureDetector.onTouchEvent(event);
                 if (event.getAction() == MotionEvent.ACTION_DOWN) {
                     state = 1;
                     x_start = event.getX();
                 }
                 if (event.getAction() == MotionEvent.ACTION_UP) {
                     state = 0;
                     x_start = 0;
                 }
                 if (event.getAction() == MotionEvent.ACTION_MOVE) {
                     if (state == 1) {
                         if (mMySurfaceCallback != null
                                 && mMySurfaceCallback.mMyDraw != null) {
                             float xEnd = event.getX();
                             float x_changed = (float) ((xEnd - x_start) / 1.3);
                             if (Math.abs(x_changed) > 5) {
                                 Log.i("PDWY", "移动了 " + x_changed);
                                 mMySurfaceCallback.mMyDraw.onFliing(x_changed);
    
                                 x_start = xEnd;
                             }
                         }
                     }
                 }
                 return true;
             }
         });
    

6。记得计算坐标位置,当不断向左拖动,拖动到 最后时,触发一个 自定义的 事件 onScrollToEnd。订阅了该事件的对象可以在 适当的时机 “加载更多的数据”

/**
         * 拖动的范围,x > 0说明是 从左到右拖动。 x<0是从右向左拖动
         * 
         * @param x_changed
         */
        public void onFliing(float x_changed) {
            float newX = origin.x + x_changed;
            if (newX > preInit_x)
                newX = preInit_x;
            int minNewX = -((result.length) * unit_x - surfaceView1.getWidth());
            boolean isToEnd = false;// 是否到达了最后一个点。即拖到最右侧极限处。
            if (newX < minNewX) {
                newX = minNewX;
                isToEnd = true;
            }
            int x = (int) newX;
            if (x == origin.x)
                return;
            origin = new Point(x, origin.y);//更改坐标系原点的位置
            draw();

            if (isToEnd) {// 触发 到达顶点的方法。
                raiseScrollToEnd();
            }
        }

自定义事件的实现

ScrollToEndListener mScrollToEndListener;

    private void raiseScrollToEnd() {
        if (mScrollToEndListener != null)
            mScrollToEndListener.onScrollToEnd();
    }

    public void setScrollToEndListener(ScrollToEndListener scrollToEndListener) {
        mScrollToEndListener = scrollToEndListener;
    }

    public static interface ScrollToEndListener {
        public void onScrollToEnd();
    }

最后,如何使用它:

public class MainActivity extends Activity {
    SurfaceView surfaceView1;
    
    MyCustomCurve mMyCustomCurve;
    
    float[] result;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        Package pck = Package.getPackage(this.getPackageName());
        Resources resource = this.getResources();
        
        surfaceView1 = (SurfaceView)findViewById(resource.getIdentifier("surfaceView1", "id", pck.getName()));
        
        mMyCustomCurve = new MyCustomCurve(this,surfaceView1);
        
        result = new float[] { 1, 30, 50, 40, 30, 5, 15, 35, 20,3,12,15,31, 30, 50, 40, 30, 5, 15, 35, 20,3,12,15,15};
        mMyCustomCurve.setResult(result);
        
        //当读取到数据的终点时
        mMyCustomCurve.setScrollToEndListener(new ScrollToEndListener() {
            
            @Override
            public void onScrollToEnd() {
                ArrayList<Float> lst = new ArrayList<Float>();
                for (int i = 0; i < result.length; i++) {
                    lst.add(result[i]);
                }
                
                //追加新的数据,随机添加10个数字,值不大于50.
                Random r = new Random();
                for (int j = 0; j < 10; j++) {
                    lst.add(r.nextFloat() * 50);
                }
                
                float[] newArray = new float[lst.size()];
                for (int i = 0; i < lst.size(); i++) {
                    newArray[i] = lst.get(i);
                }
                result = newArray;
                //设置新的数据源
                mMyCustomCurve.setResult(result);
                Toast.makeText(MainActivity.this, "加载了一次新的数据", 0).show();
            }
        });
    }

代码下载 提取码:883c

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容