• android开发(29) 自定义曲线,可拖动,无限加载


    项目需要 做一个曲线,该曲线的数据时不断加载的。如下图,当不断向左拖动时,图形曲线要随着拖动移动,并在拖动到边界时需要加载更多数据。

    先看步骤:

    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() {
    
            }
        }

    5. 注册 手势 ,当手指拖动时,曲线要随着变化。

        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

  • 相关阅读:
    适合于小团队产品迭代的APP测试流程
    【转】软件测试上线标准
    安全性测试之修改密码
    LoadRunner 实现监控Tomcat
    【转】人生应该接受的教育
    晓光聊《小厂如何做测试》
    由测试需要多少编程知识想到的
    12款很棒的浏览器兼容性测试工具推荐
    最近感悟测试人员需要的一种能力
    APP测试功能点总结
  • 原文地址:https://www.cnblogs.com/vir56k/p/3361693.html
Copyright © 2020-2023  润新知