mpandroidchar中x轴和y轴都必须是char截取字符串串类型吗

4313人阅读
IOS开发(224)
在做项目的时候,要建立一个字符大小不定的变量;最开始用char *param;然后在后面用时直接使用memcpy函数对其复制,结果导致错误;后来在网上搜了一下,在调用memcpy之前先用(char*)malloc()对其开辟内存,这样问题就解决了
以下内容来至:http://topic.csdn.net/u//2c-43bc-b11a-7e7dfb554881.html
char c[]=&hello world&会为C开辟空间然后把hello word复制进去
而char * c=&hello world&; 仅仅让c指向字符串,保存字符串的地址
char c1[]=&hello world&;
char c2[]=&hello world&;
c1和c2是开辟的两个不同的空间,彼此地址不同,分别把hello world 复制进去
char * c1=&hello world&;
char * c2=&hello world&;
时c1和c2的值相同,都存的是hello world 这个字符串常量的首地址
char * c=&hello world&;
把c隐式转换为const char*指针了
是数组的话就不会了
深入理解const char*p,char const*p,char *const p,const char **p,char const**p,char *const*p,char**const p
一、可能的组合:
(1)const char*p
(2)char const*p
(3)char *const p
(4)const char **p
(5)char const**p
(6)char *const *p
(7)char **const p
当然还有在(5)、(6)、(7)中再插入一个const的若干情况,不过分析了以上7中,其他的就可类推了!
二、理解助记法宝:
1。关键看const 修饰谁。
2。由于没有&const *的运算,若出现&const
*&的形式,则const实际上是修饰前面的。
比如:char const*p,由于没有const*运算,则const实际上是修饰前面的char,因此char const*p等价于const char*p。也就是说上面7种情况中,(1)和(2)等价。 同理,(4)和(5)等价。在(6)中,由于没有const*运算,const实际上修饰的是前面的char*,但不能在定义时转换写成 const(char *)*p,因为在定义是&()&是表示函数。
三、深入理解7种组合
(0)程序 在执行时为其开辟的空间皆在内存(RAM)中,而RAM里的内存单元是可读可写 的;指针只是用来指定或定位要操作的数据的工具,只是用来读写RAM里内存单元的工作指针 。若对指针不加任何限定,程序中一个指针可以指向RAM中的任意位置(除了系统敏感区,如操作系统内核所在区域)并对其指向的内存单元进行读和写操作(由RAM的可读可写属性决定);RAM里内存单元的可读可写属性不会因为对工作指针的限定而变化(见下面的第4点),而所有对指针的各种const限定说白了只是对该指针
的 读写权限 (包括读写位置)进行了限定&。
(1)char *p:p是一个工作指针,可以用来对任意位置&(非系统敏感区域)进 行读操作和写操作 ,一次读写一个字节(char占一个字节)。
(2)const char*p或者char const *p(因为没有const*p运算,因此const修饰的还是前面的char):可以对任意位置(非系统敏感区域)进行“只读” 操作。(“只读”是相对于char *p来说所限定的内容)
(3)char *const p(const 修饰的是p):只能对“某个固定的位置” 进 行读写操作,并且在定义p时就必须初始化(因为在后面不能执行“p=..”的操作,因此就不能在后面初始化,因此只能在定义时初始化)。(“某个固定的位 置”是相对于char *p来说所限定的内容)
可以总结以上3点为:char *p中的指针p通常是”万能”的工作指针 ,而(2)和(3)只是在(1)的基础上加了些特定的限制 ,这些限制在程序中并不是必须的,只是为了防止程序员的粗心大意而产生事与愿违的错 误。
另外,要明白“每块内存空间都可有名字;每块内存空间内容皆可变(除非有所限) ” 。比如函数里定义的char s[]=&hello&;事实上在进程的栈内存里开辟了6个变量共6个字节的空间,其中6个字符变量的名字分别为:s1[0]、s1[1]、 s1[2]、s1[3]、s1[4]、s1[5](内容是'\0')
待验证 : 还有一个4字节的指针变量s 。不过s是“有所限制”的,属于char *const类型,也就是前面说的 (3)这种情况,s一直指向s[0], 即(*s==s[0]=='h'),可以通过*s='k'来改变s所指向的 s[0]的值,但不能执行(char *h=“aaa”;s=h;)来对s另外赋值。
(4)上面的(2)和(3)只是对p进行限定,没有也不能对p所指向的空间进行限定,对于&char s[]=&hello&;const char*p=s;& 虽然不能通过*(p+i)='x'或者p[i]='x'来修改数组元素s[0]~s[4]的值,但可以通过*(s+i)='x'或者s[i]='x'来修改原数组元素的值--RAM里内存单元的可读可写属性不因对工作指针的限定而改变,而只会因对其本身的限定而改变。如const char c=‘A’,c是RAM里一个内存单元(8字节)的名字,该内存单元的内容只可读,不可写。
(5)const char **p或者char const**p :涉及两个指针p和 *p。由于const修饰char ,对指针p没有任何限定,对指针*p进行了上面情况(2)的限定。
(6)char *const *p:涉及两个指针p和 *p。由于const修饰前面的char*,也就是对p所指向的内容*p进行了限定(也属于前面的情况(2))。而对*p来说,由于不能通过&*p=...&来进行另外赋值,因此属于前面的情况(3)的限定。
(7)char **const p : 涉及两个指针p和 *p,const修饰p,对p进行上面情况(3)的限定,而对*p,没有任何限定。
四、关于char **p 、const char **p的类型相容性问题
char *p1;const *p2=p1;//合法
char **p1;const char**p2=p1;//不合法,会有警告warning: initialization from incompatible pointer type
char **p1;char const**p2=p1;//不合法,会有警告warning: initialization from incompatible pointer type
char**p1;char*const*p2=p1;//合法
2。判断规则
明确const修饰的对象!对于指针p1,和p2,若要使得p2=p1成立,则可读做 :
“p1是指向X类型的指针,p2是指向“带有const限定”的X类型的指针 “。只要二者的X类型一样,就是合法的。
char *p1;const *p2=p1;//合法:p1是指向(char)类型的指针,p2是指向“带有const限定&的(char)类型的指针。
char **p1;const char**p2=p1;//不合法:p1是指向(char*)类型的指针,p2是指向 ((const char)*)类型的指针。
char **p1;char const**p2=p1;//不合法;与上等价。
char**p1;char*const*p2=p1;//合法: p1是指向(char *)类型的指针,p2是指向“带有const限定&的(char*)类型的指针。
1。 含有const的单层或双层指针的统一读法:
“p是一个指针,是一个[“带有const限定”的]指向[”带有const限定”的]X类型的指针”。
l例如:const char* const *p就是说:p是一个带有const限定的指向带有const限定的(char*)类型的指针。
2。定义时const修饰的对象是确定的,但不能在定义时加括号,不然就和定义时用“()”表示的函数类型相混淆了!因此定义时不能写(char *)const *p或者(const char) **p。
六、问题探讨(由于博文后的留言有字符数目限制,将回复移到这里)
问题1 (见博文后留言):讲解非常好,不过有个问题想探讨下: 例如: const char wang[]={&wang&}; char *p; p= 是错误的。 所以char *p中的P不能指向常变量。 (1)需要补充纠正。
回复 : 你好!谢谢指正!我在ubuntu 10.04(gcc 4.4.3)下做了如下测试:&
//test_const.c
#include&stdio.h&
int main()
const char wang[]={&wang&};
printf(&p is %s\n&,p);
gcc -o test_const test_const.c
输出如下 :
test_const.c: In function ‘main’:
test_const.c:17: warning: assignment discards qualifiers from pointer target type
./test_const
结论: 根据本博文中第四点--相容性问题,将const型的wang赋值给p是不合法的。但编译器对其的处理只是警告,因此执行时通过p修改了只读区域的数据。这应该是该编译器处理不严所致后果,不知你用的什么编译器?
问题2 回答&&提到的问题
int main() {
const char* s1 = &test&;
char *s2 = s1;
s2 = &It's modified!&;
printf(&%s\n&,s1);
out: It's modified!;
这样也可以吗? 照我的理解岂不是const限定符在c语言里只是摆设一个?
(1)首先,以上代码编译时会出错warning: initialization discards qualifiers from pointer target type,
因为char *s2 = s1和问题1提到的一样,不符合相容规则。
(2)输出结果是正确的,代码分析如下:
int main() {
const char* s1 = &test&; // 在只读数据区(objdump -h test后的.rodata区)开辟5字节存储&test&,并用s1指向首字符‘t’。&
char *s2 = s1; // s2也指向只读数据区中“test”的首字符't'。&
s2 = &It's modified!&; // 在只读数据区开辟15字节存储&It's modified!&,并将s2由指向't'转而指向&It's modified!&的首字符'I'。&
printf(&%s\n&,s1); // 从s1所指的‘t’开始输出字符串&test&。&
(3)总结:提问者的误区在于,误以为s2 = &It's modified!&是对“test”所在区域的重新赋值,其实这里只是将“万能”工作指针s2指向另外一个新开辟的区域而已。比如若在char *s2 = s1后再执行s2[2]='a'则是对“test”的区域进行了写操作,执行时会出现段错误。但这个段错误其实与const没有关系,因为“test”这块区域本身就是只读的。为了防止理解出错,凡事对于对指针的赋值(比如 s2 = &It's modified!& ),则将其读做:将s2指向“ It's modified!
”所在区域的首字符。
(4)额外收获:执行gcc -o test test.c后,“test”、“It's modified!”、&%s\n&都被作为字符串常量存储在二进制文件test的只读区
域 (.rodata)。事实上,一个程序从编译到运行,对变量空间分配的情况如下:
A。赋值了的全局变量或static变量=&放在可执行文件的.data段。
B。未赋值的全局变量或static变量=&放在可执行文件的.bss段。
C。代码中出现的字符串常量或加了const的A=&放在可执行文件的.rodata段。
D。一般的局部变量=&在可执行文件中不占空间,在该二进制文件作为进程在内存中运行时才为它分配栈空间。
E。代码中malloc或new出的变量=&在可执行文件中不占空间,在该二进制文件作为进程在内存中运行时才为它分配堆空间。
问题3:(待进一步分析) 验证博文中 三(3)提到的是否为s分配空间,初步分析结果为:不分配!文中的s只是s[0]的地址的代号而已。
#include&stdio.h&
int main() {
char s1[] = &test&;
char s2[] =&test2&;
printf(&the address of a is %u\n&,&a);
printf(&s1 is %u\n&,s1);
printf(&the address of s1 is %u\n&,&s1);
printf(&the address of b is %u\n&,&b);
printf(&s2 is %u\n&,s2);
printf(&the address of s2 is %u\n&,&s2);
输出结果:
the address of a is
the address of s1 is
the address of b is
the address of s2 is
由结果可以看出,编译器做了些优化。
七、其他相关经典文章转载
王海宁,华清远见嵌入式学院讲师,对const关键字的理解
目前在进行C语言补习时,发现很多的同学对于const这个关键字的理解存在很大的误解。现在总结下对这个关键字理解上的误区,希望在以后的编程中,能够灵活使用const这个关键字。
1、 const修饰的变量是常量还是变量
对于这个问题,很多同学认为const修饰的变量是不能改变,结果就误认为该变量变成了常量。那么对于const修饰的变量该如何理解那?
下面我们来看一个例子:
char buf[4];
const int a = 0;
这个比较容易理解,编译器直接报错,原因在于“a = 10;”这句话,对const修饰的变量,后面进行赋值操作。这好像说明了const修饰的变量是不能被修改的,那究竟是不是那,那么下面我们把这个例子修改下:
char buf[4];
const int a = 0;
buf[4] = 97;
printf(“the a is %d\n”,a);
其中最后一句printf的目的是看下变量a的值是否改变,根据const的理解,如果const修饰的是变量是不能被修改的话,那么a的值一定不会改变,肯定还是0。但是在实际运行的结果中,我们发现a的值已经变为97了。这说明const修饰的变量a,已经被我们程序修改了。
那综合这两个例子,我们来分析下,对于第二例子,修改的原因是buf[4]的赋值操作,我们知道buf[4]这个变量已经造成了buf这个数组变量的越界访问。buf数组的成员本身只有0,1,2,3,那么buf[4]访问的是谁那,根据局部变量的地址分配,可以知道buf[4]的地址和int a的地址是一样,那么buf[4]实际上就是访问了const int a;那么对buf[4]的修改,自然也修改了const int a的空间,这也是为什么我们在最后打印a的值的时候看到了97这个结果。
那么我们现在可以知道了,const修饰的变量是不具备不允许修改的特性的,那么对于第一个例子的现象我们又如何解释那。
第一个例子,错误是在程序编译的时候给出的,注意这里,这个时候并没有生成可执行文件,说明const修饰的变量可否修改是由编译器来帮我们保护了。而第二个例子里,变量的修改是在可执行程序执行的时候修改的,说明a还是一个变量。
综上所述,我们可以得出一个结论,那就是const修饰的变量,其实质是告诉程序员或编译器该变量为只读,如果程序员在程序中显示的修改一个只读变量,编译器会毫不留情的给出一个error。而对于由于像数组溢出,隐式修改等程序不规范书写造成的运行过程中的修改,编译器是无能为力的,也说明const修饰的变量仍然是具备变量属性的。
2、 被const修饰的变量,会被操作系统保护,防止修改
如果对于第一个问题,有了理解的话,那么这个问题,就非常容易知道答案了。Const修饰的变量是不会被操作系统保护的。
其原因是操作系统只保护常量,而不会保护变量的读写。那么什么是常量?比如“hello world”这个字符串就是被称为字符串常量。
对于这个问题的另一种证明方法,可以看下面这个程序:
char *buf = “hello world”;
printf(“the &a is %p, the buf is %p\n”,&a, buf);
可以发现buf保存的地址是在0x这个地址附近的,而a的地址是在0xbf000000这个地址附近的,而0x附近的地址在我们linux操作系统上是代码段。这也说明了常量和变量是存放在不同区域的,自然操作系统是会保护常量的。
如果我们知道这个道理后,再看下面的题目:
char *buf = “hello”;
buf[0] = ‘a’;
printf(“the buf is %s\n”,buf);
我们可以思考下,这个程序的运行结果会是什么呢?
//////////////////////////////////////////////////////////////////////////////////////////////////////////////再次编辑
问题引入:
在实习过程中发现了一个以前一直默认的错误,同样char *c = &abc&和char c[]=&abc&,前者改变其内
容程序是会崩溃的,而后者完全正确。
程序演示:
测试环境Devc++
#include &iostream&
&&& char *c1 = &abc&;
&&& char c2[] = &abc&;
&&& char *c3 = ( char* )malloc(3);
&&& c3 = &abc&;
&&& printf(&%d %d %s\n&,&c1,c1,c1);
&&& printf(&%d %d %s\n&,&c2,c2,c2);
&&& printf(&%d %d %s\n&,&c3,c3,c3);
&&& getchar();
参考资料:
首先要搞清楚编译程序占用的内存的分区形式:
一、预备知识—程序的内存分配
一个由c/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack)—由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于
数据结构中的栈。
2、堆区(heap)—一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据
结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)—全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态
变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统
4、文字常量区—常量字符串就是放在这里的。程序结束后由系统释放。
5、程序代码区
这是一个前辈写的,非常详细
//main.cpp
&& int a=0;&&&& //全局初始化区
&& char *p1;&&& //全局未初始化区
&&& char s[]=&abc&;&&& //栈
&&& char *p2;&&&&&&&&& //栈
&&& char *p3=&123456&;&&& //在常量区,p3在栈上。
&&& static int c=0;&&& //全局(静态)初始化区
&&& p1 = (char*)malloc(10);
&&& p2 = (char*)malloc(20);&&& //分配得来得10和20字节的区域就在堆区。
&&& strcpy(p1,&123456&);&&& //放在常量区,编译器可能会将它与p3所向&123456&优化成一个
二、堆和栈的理论知识
2.1申请方式
由系统自动分配。例如,声明在函数中一个局部变量系统自动在栈中为b开辟空间
需要程序员自己申请,并指明大小,在c中malloc函数
如p1=(char*)malloc(10);
在C++中用new运算符
如p2=(char*)malloc(10);
但是注意p1、p2本身是在栈中的。
申请后系统的响应
栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,
会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将
该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大
小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正
好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。
2.3申请大小的限制
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地
址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译
时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地
址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的
虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
2.4申请效率的比较:
栈:由系统自动分配,速度较快。但程序员是无法控制的。
堆:是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.
另外,在WINDOWS下,最好的方式是用Virtual Alloc分配内存,他不是在堆,也不是在栈,而是直接在进
程的地址空间中保留一块内存,虽然用起来最不方便。但是速度快,也最灵活。
2.5堆和栈中的存储内容
栈:在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的
地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变
量。注意静态变量是不入栈的。
当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主
函数中的下一条指令,程序由该点继续运行。
堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容由程序员安排。
2.6存取效率的比较
char s1[]=&aaaaaaaaaaaaaaa&;
char *s2=&bbbbbbbbbbbbbbbbb&;
aaaaaaaaaaa是在运行时刻赋值的;
而bbbbbbbbbbb是在编译时就确定的;
但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。
voidmain()
char c[]=&&;
char *p=&&;
对应的汇编代码
10:a=c[1];
DF1movcl,byteptr[ebp-0Fh]
DFCmovbyteptr[ebp-4],cl
11:a=p[1];
B55ECmovedx,dwordptr[ebp-14h]
01moval,byteptr[edx+1]
FCmovbyteptr[ebp-4],al
第一种在读取时直接就把字符串中的元素读到寄存器cl中,而第二种则要先把指针值读到edx中,在根据
edx读取字符,显然慢了。
堆和栈的区别可以用如下的比喻来看出:
使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会
切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。
使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。
自我总结:
char *c1 = &abc&;实际上先是在文字常量区分配了一块内存放&abc&,然后在栈上分配一地址给c1并指向
这块地址,然后改变常量&abc&自然会崩溃
然而char c2[] = &abc&,实际上abc分配内存的地方和上者并不一样,可以从
2293624 看出,完全是两块地方,推断4199056处于常量区,而2293624处于栈区
2293620 这段输出看出三个指针分配的区域为栈区,而且是从高地址到低地址
9056 abc 看出编译器将c3优化指向常量区的&abc&
继续思考:
#include &iostream&
&&& char *c1 = &abc&;
&&& char c2[] = &abc&;
&&& char *c3 = ( char* )malloc(3);
&&& //&& *c3 = &abc& //error
&&& strcpy(c3,&abc&);
&&& c3[0] = 'g';
&&& printf(&%d %d %s\n&,&c1,c1,c1);
&&& printf(&%d %d %s\n&,&c2,c2,c2);
&&& printf(&%d %d %s\n&,&c3,c3,c3);
&&& getchar();
写成注释那样,后面改动就会崩溃
可见strcpy(c3,&abc&);abc是另一块地方分配的,而且可以改变,和上面的参考文档说法有些不一定,
&&相关文章推荐
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:902778次
积分:9069
积分:9069
排名:第1816名
原创:79篇
转载:241篇
评论:50条
(1)(3)(6)(5)(14)(2)(2)(9)(4)(1)(4)(3)(1)(7)(8)(6)(2)(6)(18)(20)(10)(9)(6)(17)(15)(7)(40)(16)(9)(18)(40)(12)1918人阅读
android应用开发(2)
先把要写的写下来,有时间再详写
& & 之前学MPAndroidChat主要看了这个人的博文http://blog.csdn.net/shineflowers/article/details/,但是发现和github上的内容有出入,仔细研究了后发现github上的代码原来一直在更新,博主只是因为版本低所以不一样,所以我从github上导出工程后再导出jar包就是最新的了。
&& 下面的中文说明/p/ca?nomobile=yes
---------------------------------------------------------------------------------------------------------------------------------------------------
&&& 今天算是有时间了 ,抽点时间把图表内容总结一下,有部分是copy上述引用博文的,有部分是自己总结的,代码如下:
package myapp.
import java.util.ArrayL
import android.app.A
import android.graphics.C
import android.os.B
import com.github.mikephil.charting.charts.PieC
import com.github.ponents.L
import com.github.mikephil.charting.data.E
import com.github.mikephil.charting.data.PieD
import com.github.mikephil.charting.data.PieDataS
public class PieGraphActivity extends Activity {
PieChart pieC
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pie_graph);
setChart();
public void init(){
pieChart=(PieChart)findViewById(R.id.pie_chart);
public void setChart(){
ArrayList&String& names=new ArrayList&String&();
names.add(&used&);
names.add(&left&);
ArrayList&Entry& sizes=new ArrayList&Entry&();
sizes.add(new Entry(10,0));
sizes.add(new Entry(90,1));
ArrayList&Integer& colors=new ArrayList&Integer&();
colors.add(Color.parseColor(&#FFBB33&));
colors.add(Color.parseColor(&#CCCCCC&));
PieDataSet pieDataSet=new PieDataSet(sizes,&&);//参数:颜色栏显示颜色目录、
//pieDataSet.setDrawValues(false);//是否在块上面显示值以及百分百
//pieDataSet.setSliceSpace(0f);//块间距
pieDataSet.setColors(colors);
//DisplayMetrics metrics=this.getResources().getDisplayMetrics();
PieData pieData=new PieData(names,pieDataSet);
pieChart.setTransparentCircleRadius(0f);//设置大圆里面透明小圆半径,和洞不是一个圆
pieChart.setDrawHoleEnabled(true);
//pieChart.setHoleColorTransparent(true);//设置中心洞是否透明:true为黑,false为白
pieChart.setHoleRadius(0f);//设置大圆里面的无色圆的半径(洞...)
pieChart.setDescription(&&);//参数:右下角显示图形描述
pieChart.setDrawCenterText(false);//不显示图中心文字
pieChart.setCenterText(&traffic graph&);//图中心文字
pieChart.setRotationEnabled(false);//不能手动旋转
//pieChart.setDrawMarkerViews(false);
//pieChart.setDrawSliceText(false);//块的文本是否显示
pieChart.setData(pieData);
Legend legend=pieChart.getLegend();
legend.setEnabled(false);//是否显示图形说明,必须要放在setData后,否则出错
//两个参数有不同的意思:
//durationMillisX:每个块运行到固定初始位置的时间
//durationMillisY: 每个块到绘制结束时间
pieChart.animateXY();//设置动画(参数为时间)
显示结果:
package myapp.
import java.util.ArrayL
import android.app.A
import android.graphics.C
import android.os.B
import android.view.WindowM
import com.github.mikephil.charting.charts.BarC
import com.github.ponents.L
import com.github.ponents.XA
import com.github.ponents.XAxis.XAxisP
import com.github.ponents.YA
import com.github.ponents.YAxis.YAxisLabelP
import com.github.mikephil.charting.data.BarD
import com.github.mikephil.charting.data.BarDataS
import com.github.mikephil.charting.data.BarE
public class RecGraphActivity extends Activity {
BarChart barC
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_rec_graph);
setData();
public void init(){
barChart=(BarChart)findViewById(R.id.bar_chart);
public void setData(){
ArrayList&String& names=new ArrayList&String&();
names.add(&1月1日&);
names.add(&1月2日&);
names.add(&1月3日&);
names.add(&1月4日&);
names.add(&1月5日&);
names.add(&1月6日&);
names.add(&1月7日&);
names.add(&1月8日&);
names.add(&1月9日&);
//大小(高低)
ArrayList&BarEntry& sizes=new ArrayList&BarEntry&();
sizes.add(new BarEntry(80,0));
sizes.add(new BarEntry(70,1));
sizes.add(new BarEntry(60,2));
sizes.add(new BarEntry(50,3));
sizes.add(new BarEntry(40,4));
sizes.add(new BarEntry(30,5));
sizes.add(new BarEntry(20,6));
sizes.add(new BarEntry(10,7));
sizes.add(new BarEntry(0,8));
BarDataSet barDataSet=new BarDataSet(sizes,&&);
barDataSet.setColor(Color.parseColor(&#FFBB33&));
BarData barData=new BarData(names,barDataSet);
barChart.setDescription(&&);//数据描述
barChart.setNoDataTextDescription(&No Data&);//没有数据时显示
//barChart.setDragEnabled(false);//拖拽(蛋疼)
barChart.setScaleEnabled(true);//手动缩放效果
barChart.setPinchZoom(false);//xy轴同时缩放,和setScaleEnabled一起使用
barChart.setHighlightPerTapEnabled(true);//按下时高亮显示
//barChart.setDrawGridBackground(false);
//barChart.setDrawBorders(false);//画布边框
//barChart.setVisibleXRange(7);
//barChart.setMaxVisibleValueCount(6);
barChart.setDrawBarShadow(false);//设置矩形阴影不显示
barChart.setBackgroundColor(Color.parseColor(&#FFFFFF&));//设置背景颜色
barChart.setMinOffset(0);//=padding
barChart.setDrawValueAboveBar(true);
barChart.setData(barData);
barChart.animateXY();//设置动画
Legend legend=barChart.getLegend();//取消图形说明
legend.setEnabled(false);
//获取X轴坐标
XAxis xAxis=barChart.getXAxis();
xAxis.setPosition(XAxisPosition.BOTTOM);//X坐标位于图标底部
xAxis.setDrawGridLines(false);
xAxis.setSpaceBetweenLabels(2);//设置名字names之间的间距
//获取Y轴右坐标
YAxis yAxisR=barChart.getAxisRight();
yAxisR.setEnabled(false);
yAxisR.setDrawGridLines(false);
//获取Y轴左坐标
YAxis yAxisL=barChart.getAxisLeft();
yAxisL.setEnabled(false);
yAxisL.setDrawGridLines(false);
显示结果:
遇到的相关问题:
&&& 1:barChart的横坐标值没有显示。原因:视图中图表控件高度是match_parent,需要增加属性android:layout_marginBottom=&35dp&(或者其他值)
&&& 2:怎么初始化直方图上出现柱子个数,以及柱子宽度。(悲剧,看源码都看晕了,还是没弄懂555....)
--------------------------------------------------------------------------------------------------------------------------------------------------
&&& 大叫好,今天又有时间写博文了,之前上传了图片没看,今天一瞧真TM大,尴尬了......
&&&& 嗯,继续解决上述第二个问题,今天看了一天的源代码,是在没有找到能够初始化柱子的函数,悲剧,所以只能从其他方法入手,我的想法是让柱子的总数一定,比如30天,有30个数据,但是我要它只显示7个数据,我们可以让直方图放大四倍,这样显示在屏幕上的就是7个数据了,好了有了目标就可以动手了
&&& 首先我们发现直方图自己就有缩放功能,于是我们看看能不能修改源代码,自己新增一下借口和改一下源代码:
&&& 这段代码是在BarLineChartTouchListener类中,处理触摸事件
public boolean onTouch(View v, MotionEvent event) {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
mVelocityTracker.addMovement(event);
if (event.getActionMasked() == MotionEvent.ACTION_CANCEL) {
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker =
if (mTouchMode == NONE) {
mGestureDetector.onTouchEvent(event);
if (!mChart.isDragEnabled() && (!mChart.isScaleXEnabled() && !mChart.isScaleYEnabled()))
// Handle touch events here...
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
startAction(event);
stopDeceleration();
saveTouchStart(event);
case MotionEvent.ACTION_POINTER_DOWN:
if (event.getPointerCount() &= 2) {
mChart.disableScroll();
saveTouchStart(event);
// get the distance between the pointers on the x-axis
mSavedXDist = getXDist(event);
// get the distance between the pointers on the y-axis
mSavedYDist = getYDist(event);
// get the total distance between the pointers
mSavedDist = spacing(event);
if (mSavedDist & 10f) {
if (mChart.isPinchZoomEnabled()) {
mTouchMode = PINCH_ZOOM;
if (mSavedXDist & mSavedYDist)
mTouchMode = X_ZOOM;
mTouchMode = Y_ZOOM;
// determine the touch-pointer center
midPoint(mTouchPointCenter, event);
case MotionEvent.ACTION_MOVE:
if (mTouchMode == DRAG) {
mChart.disableScroll();
performDrag(event);
} else if (mTouchMode == X_ZOOM || mTouchMode == Y_ZOOM || mTouchMode == PINCH_ZOOM) {
mChart.disableScroll();
if (mChart.isScaleXEnabled() || mChart.isScaleYEnabled())
performZoom(event);
} else if (mTouchMode == NONE
&& Math.abs(distance(event.getX(), mTouchStartPoint.x, event.getY(),
mTouchStartPoint.y)) & 5f) {
if (mChart.hasNoDragOffset()) {
if (!mChart.isFullyZoomedOut() && mChart.isDragEnabled()) {
mTouchMode = DRAG;
mLastGesture = ChartGesture.DRAG;
if (mChart.isHighlightPerDragEnabled())
performHighlightDrag(event);
} else if (mChart.isDragEnabled()) {
mLastGesture = ChartGesture.DRAG;
mTouchMode = DRAG;
case MotionEvent.ACTION_UP:
final VelocityTracker velocityTracker = mVelocityT
final int pointerId = event.getPointerId(0);
puteCurrentVelocity(1000, Utils.getMaximumFlingVelocity());
final float velocityY = velocityTracker.getYVelocity(pointerId);
final float velocityX = velocityTracker.getXVelocity(pointerId);
if (Math.abs(velocityX) & Utils.getMinimumFlingVelocity() ||
Math.abs(velocityY) & Utils.getMinimumFlingVelocity()) {
if (mTouchMode == DRAG && mChart.isDragDecelerationEnabled()) {
stopDeceleration();
mDecelerationLastTime = AnimationUtils.currentAnimationTimeMillis();
mDecelerationCurrentPoint = new PointF(event.getX(), event.getY());
mDecelerationVelocity = new PointF(velocityX, velocityY);
Utils.postInvalidateOnAnimation(mChart); // This causes computeScroll to fire, recommended for this by Google
if (mTouchMode == X_ZOOM ||
mTouchMode == Y_ZOOM ||
mTouchMode == PINCH_ZOOM ||
mTouchMode == POST_ZOOM) {
// Range might have changed, which means that Y-axis labels
// could have changed in size, affecting Y-axis size.
// So we need to recalculate offsets.
mChart.calculateOffsets();
mChart.postInvalidate();
mTouchMode = NONE;
mChart.enableScroll();
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker =
endAction(event);
case MotionEvent.ACTION_POINTER_UP:
Utils.velocityTrackerPointerUpCleanUpIfNecessary(event, mVelocityTracker);
mTouchMode = POST_ZOOM;
case MotionEvent.ACTION_CANCEL:
mTouchMode = NONE;
endAction(event);
// Perform the transformation, update the chart
// if (needsRefresh())
mMatrix = mChart.getViewPortHandler().refresh(mMatrix, mChart, true);
// indicate event was handled
}&&& 然后缩放时间由performZoom(event)方法执行,其实在这里我们就看到了一个单词Zoom,查了一下,其含义是:(有道词典),然后继续看代码
private void performZoom(MotionEvent event) {
if (event.getPointerCount() &= 2) {
OnChartGestureListener l = mChart.getOnChartGestureListener();
// get the distance between the pointers of the touch
float totalDist = spacing(event);
if (totalDist & 10f) {
// get the translation
PointF t = getTrans(mTouchPointCenter.x, mTouchPointCenter.y);
// take actions depending on the activated touch
if (mTouchMode == PINCH_ZOOM) {
mLastGesture = ChartGesture.PINCH_ZOOM;
float scale = totalDist / mSavedD // total scale
boolean isZoomingOut = (scale & 1);
boolean canZoomMoreX = isZoomingOut ?
mChart.getViewPortHandler().canZoomOutMoreX() :
mChart.getViewPortHandler().canZoomInMoreX();
float scaleX = (mChart.isScaleXEnabled()) ? scale : 1f;
float scaleY = (mChart.isScaleYEnabled()) ? scale : 1f;
if (mChart.isScaleYEnabled() || canZoomMoreX) {
Log.v(&performZoom&, &PINCH_ZOOM :scaleX:&+scaleX+& scaleY &+scaleY);
mMatrix.set(mSavedMatrix);
mMatrix.postScale(scaleX, scaleY, t.x, t.y);
if (l != null){
l.onChartScale(event, scaleX, scaleY);
} else if (mTouchMode == X_ZOOM && mChart.isScaleXEnabled()) {
mLastGesture = ChartGesture.X_ZOOM;
float xDist = getXDist(event);
float scaleX = xDist / mSavedXD // x-axis scale
boolean isZoomingOut = (scaleX & 1);
boolean canZoomMoreX = isZoomingOut ?
mChart.getViewPortHandler().canZoomOutMoreX() :
mChart.getViewPortHandler().canZoomInMoreX();
if (canZoomMoreX) {
mMatrix.set(mSavedMatrix);
mMatrix.postScale(scaleX, 1f, t.x, t.y);
Log.v(&performZoom&, &scaleX:&+scaleX);
Log.v(&performZoom&, &l!=null:&+(l != null));
Log.v(&performZoom&, &isZoomingOut:&+isZoomingOut);
Log.v(&performZoom&, &canZoomMoreX:&+canZoomMoreX);
Log.v(&performZoom&, &class :&+this.getClass().getName());
if (l != null){
l.onChartScale(event, scaleX, 1f);
Log.v(&performZoom&, &onChartScale :scaleX:&+scaleX);
Log.v(&performZoom&, &class ::&+this.getClass().getName());
} else if (mTouchMode == Y_ZOOM && mChart.isScaleYEnabled()) {
mLastGesture = ChartGesture.Y_ZOOM;
float yDist = getYDist(event);
float scaleY = yDist / mSavedYD // y-axis scale
mMatrix.set(mSavedMatrix);
// y-axis comes from top to bottom, revert y
mMatrix.postScale(1f, scaleY, t.x, t.y);
if (l != null)
l.onChartScale(event, 1f, scaleY);
}&&& 缩放方法最后执行到了l.onChartScale(event, 1f, scaleY);这一句,然后。。。就没有然后了,找不到这句函数的实现位置,只找到了借口,啊.......
&&& 虽然线索断了,但是也不能就此放弃,这个过程中我们知道了一个单词Zoom,咦,是不是有点熟悉,在BarChart的方法中好像有这些方法,嗯,没错:
* Zooms in by 1.4f, into the charts center. center.
public void zoomIn() {
Matrix save = mViewPortHandler.zoomIn(getWidth() / 2f, -(getHeight() / 2f));
mViewPortHandler.refresh(save, this, true);
// Range might have changed, which means that Y-axis labels
// could have changed in size, affecting Y-axis size.
// So we need to recalculate offsets.
calculateOffsets();
postInvalidate();
* Zooms out by 0.7f, from the charts center. center.
public void zoomOut() {
Matrix save = mViewPortHandler.zoomOut(getWidth() / 2f, -(getHeight() / 2f));
mViewPortHandler.refresh(save, this, true);
// Range might have changed, which means that Y-axis labels
// could have changed in size, affecting Y-axis size.
// So we need to recalculate offsets.
calculateOffsets();
postInvalidate();
* Zooms in or out by the given scale factor. x and y are the coordinates
* (in pixels) of the zoom center.
* @param scaleX if & 1f --& zoom out, if & 1f --& zoom in
* @param scaleY if & 1f --& zoom out, if & 1f --& zoom in
* @param x
* @param y
public void zoom(float scaleX, float scaleY, float x, float y) {
Matrix save = mViewPortHandler.zoom(scaleX, scaleY, x, -y);
mViewPortHandler.refresh(save, this, true);
// Range might have changed, which means that Y-axis labels
// could have changed in size, affecting Y-axis size.
// So we need to recalculate offsets.
calculateOffsets();
postInvalidate();
}&&& 似乎可以叹口气了,答案就在这里,我们直接调用barChart.zoom(4,1,0,0);方法,就可实现我们的目的了
&&& (虽然过程似乎超乎意料,但是结果像是也在情理之中,就这样把)
&&相关文章推荐
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:20069次
排名:千里之外
原创:39篇
(2)(1)(1)(1)(11)(10)(12)(5)

我要回帖

更多关于 char截取字符串 的文章

 

随机推荐