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
android开发(29) 自定义曲线,可拖动,无限加载的更多相关文章
- Vue.js 开发实践:实现精巧的无限加载与分页功能
本篇文章是一篇Vue.js的教程,目标在于用一种常见的业务场景--分页/无限加载,帮助读者更好的理解Vue.js中的一些设计思想.与许多Todo List类的入门教程相比,更全面的展示使用Vue.js ...
- 【Android开发那点破事】打开APP加载页面实现
今天的破事呢就说说APP加载页面的实现.一般情况下,当APP打开的时候,我们需要做很多事情,比如检查网络连接啊,初始化一些配置啊等等.我们可以让这些事情在APP完全打开之前做完,然后呢在打开的过程中显 ...
- android开发之自定义组件
android开发之自定义组件 一:自定义组件: 我认为,自定义组件就是android给我们提供的的一个空白的可以编辑的图片,它帮助我们实现的我们想要的界面,也就是通过自定义组件我们可以把我们要登入的 ...
- JRoll 2 使用文档(史上最强大的下拉刷新,滚动,无限加载插件)
概述 说明 JRoll,一款能滚起上万条数据,具有滑动加速.回弹.缩放.滚动条.滑动事件等功能,兼容CommonJS/AMD/CMD模块规范,开源,免费的轻量级html5滚动插件. JRoll第二版是 ...
- Qt实现小功能之列表无限加载(创意很不错:监听滚动条事件,到底部的时候再new QListWidgetItem)
概念介绍 无限加载与瀑布流的结合在Web前端开发中的效果非常新颖,对于网页内容具备较好的表现形式.无限加载并没有一次性将内容全部加载进来,而是通过监听滚动条事件来刷新内容的.当用户往下拖动滚动条或使用 ...
- Qt实现小功能之列表无限加载
概念介绍 无限加载与瀑布流的结合在Web前端开发中的效果非常新颖,对于网页内容具备较好的表现形式.无限加载并没有一次性将内容全部加载进来,而是通过监听滚动条事件来刷新内容的.当用户往下拖动滚动条或使用 ...
- Android系列之Fragment(一)----Fragment加载到Activity当中
Android上 的界面展示都是通过Activity实现的,Activity实在是太常用了.但是Activity也有它的局限性,同样的界面在手机上显示可能很好看, 在平板上就未必了,因为平板的屏幕非常 ...
- Android UI--自定义ListView(实现下拉刷新+加载更多)
Android UI--自定义ListView(实现下拉刷新+加载更多) 关于实现ListView下拉刷新和加载更多的实现,我想网上一搜就一堆.不过我就没发现比较实用的,要不就是实现起来太复杂,要不就 ...
- Android图片管理组件(双缓存+异步加载)
转自:http://www.oschina.net/code/snippet_219356_18887?p=3#comments ImageManager2这个类具有异步从网络下载图片,从sd读取本地 ...
随机推荐
- spring-cloud/spring-cloud-sleuth github 项目 mark
97 Star639 Fork335 spring-cloud/spring-cloud-sleuth CodeIssues 5Pull requests 1Projects 0WikiInsigh ...
- Google Protocol Buffers介绍
简要介绍和总结protobuf的一些关键点,从我之前做的ppt里摘录而成,希望能节省protobuf初学者的入门时间.这是一个简单的Demo. Protobuf 简介 Protobuf全称Google ...
- php7+apache2.4 (Windows7下)安装
条件: ( 电脑必须win7 sp1, .netframework4 ) 一.下载php7和apache2.4 首先下载php7的windows压缩包,到这里下载http://windows.php. ...
- 将视频转换为 HLS(HTTP Live Streaming) 协议格式文件
就是将视频文件转码(H264+ACC).分片(n个.ts文件).生成列表(.m3u8) 方便网站提供视频播放服务,提升加载速度,节省流量. 1.准备好源视频文件. 2.下载 ffmpeg(http:/ ...
- nginx 配置http重定向到https
在80端口的那个server下,添加如下: server_name www.youwebsite.com youwebsite.com; rewrite ^(.*)$ https://$host$1 ...
- jqgrid 设置为每行单选
jqgrid 不支持单选,自己自带了多选multiselect 那么单选怎么做呢,可以参考如下配置 multiselect: true, multiboxonly:true, gridComplete ...
- 使用 RestTemplate 调用 restful 服务
什么是RestTemplate? RestTemplate是Spring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效 ...
- (原创)结构体自动化转为char数组的实现
结构体自动化转换为char数组这个需求,来自于一个最近开发的一个项目,在项目开发过程中遇到一个小问题,需要将各种结构体拷贝到char数组中,这对于一个简单的结构体来说是很简单的事情,比如下面这个只有整 ...
- django rest_framework入门四-类视图APIView
上节,我们使用函数视图,用了@api_view装饰器来修饰,这一节,我们介绍类视图APIView,显然,类视图更符合面向对象的原则. 1.使用类视图APIView重写API 类视图APIView,取代 ...
- Mac使用pyenv安装Python出现The Python zlib extension was not compiled. Missing the zlib错误
Mac使用pyenv安装Python出现The Python zlib extension was not compiled. Missing the zlib错误 参考这里,详细如下: On Mac ...