• 原生Android 以面向对象的方式操作canvas


    Android 自定义view 用canvas去画图形, 都是以面向过程的方式去一笔一笔的画, 而且画的图形也不能支持添加事件, 而html, js在这方面有大量的封装好的canvas框架, 很奇怪的是android上我也没有搜到类似的封装框架, 我只是个web前端开发者, 可能是我对android不了解没有搜索到, 我就仿照html,js这一套实现了这个Android上的canvas小框架object-canvas。

    框架参照html div标签的一些特性实现的

    1. 有盒子模型,支持border,padding, 可以分别设置上下左右的样式
    2. 可以直接设置文本, 在android里显示个文字还要嵌套上一层textview
    3. 仅支持绝对布局, 这个得需要自己计算元素的位置了, 确定元素的宽,高l,eft和top, 相对布局还没实现
    4. 支持添加事件, 可以捕获和冒泡事件
    5. 直接支持滚动条, 在android里还要嵌套一个ScrollView才出滚动条
    6. 支持transform变换,支持平移, 旋转,缩放等, 支持全局坐标转自身坐标, 自身坐标转全局坐标
    7. 支持缓动动画, 支持属性动画和timeline, 动画参数可以设置往返执行, 执行次数, 缓动函数等

    当前这个框架只是抛转引玉, 没啥实用性

    开源代码: 

    object-canvasicon-default.png?t=M85Bhttps://github.com/chengxg/object-canvas

    这个图就是以canvas来画的demo

     CanvasDemoView.java

    1. package com.github.chengxg.object_canvas;
    2. import android.content.Context;
    3. import android.graphics.Bitmap;
    4. import android.graphics.BitmapFactory;
    5. import android.graphics.Canvas;
    6. import android.graphics.Color;
    7. import android.util.AttributeSet;
    8. import android.util.DisplayMetrics;
    9. import android.util.Log;
    10. import android.view.MotionEvent;
    11. import android.view.View;
    12. import com.github.chengxg.object_canvas.Anime;
    13. import com.github.chengxg.object_canvas.Body;
    14. import com.github.chengxg.object_canvas.Element;
    15. import com.github.chengxg.object_canvas.Event;
    16. import com.github.chengxg.object_canvas.shape.CicleShape;
    17. import com.github.chengxg.object_canvas.shape.ImageShape;
    18. public class CanvasDemoView extends View {
    19. public Body root = null;
    20. public int screenWidth = 0;
    21. public int screenHeight = 0;
    22. public float screenWidthDp = 0;
    23. public float screenHeightDp = 0;
    24. public CanvasDemoView(Context context, AttributeSet attrs) {
    25. super(context, attrs);
    26. DisplayMetrics dm = getResources().getDisplayMetrics();
    27. screenWidth = dm.widthPixels;
    28. screenHeight = dm.heightPixels;
    29. screenWidthDp = screenWidth / dm.density;
    30. screenHeightDp = screenHeight / dm.density;
    31. root = new Body(this);
    32. root.setDensityScale(dm.density);
    33. root.layout.setContent((float) screenWidthDp, (float) screenHeightDp);
    34. root.setBox().setBackgroundColor(0xfff2f2f2);
    35. initPage(root);
    36. }
    37. public void initPage(Element parent) {
    38. //@formatter:off
    39. Element page = new Element(); parent.addChild(page);
    40. Element section1 = new Element();page.addChild(section1);
    41. Element title = new Element();section1.addChild(title);
    42. Element content = new Element();section1.addChild(content);
    43. ImageShape leftCnt = new ImageShape();content.addChild(leftCnt);
    44. Element rightCnt = new Element();content.addChild(rightCnt);
    45. Element cntTitle = new Element();rightCnt.addChild(cntTitle);
    46. Element cntDesc = new Element();rightCnt.addChild(cntDesc);
    47. Element sectionAnimate = new Element();page.addChild(sectionAnimate);
    48. Element sectionScroll = new Element();page.addChild(sectionScroll);
    49. //@formatter:on
    50. page.getLayout().setPadding(10).setContentMatchParent(0);
    51. page.setScroll();
    52. section1.setName("testsection1").getLayout().setBorderWidth(1).setPadding(10).setContentMatchParent(150);
    53. section1.setBox().setBackgroundColor(Color.WHITE).setBorderColor(0xffcccccc).setBorderRadius(10);
    54. title.setName("testTitle").getLayout().setPadding(10, 5).setBorderBottom(1).setContentMatchParent(40);
    55. title.setTextContent("Section1").setColor(0xff333333).setTextSize(16);
    56. title.setBox().setBorderColor(0xffcccccc);
    57. content.getLayout().setPadding(5).setContentMatchParent(80).setPosition(0, title.layout.top + title.getLayout().getHeight() + 10);
    58. Bitmap picIcon = BitmapFactory.decodeResource(this.getResources(), R.drawable.picture_icon);
    59. leftCnt.getLayout().setContent(48, 48);
    60. leftCnt.setBitmap(picIcon);
    61. rightCnt.getLayout().setPosition(60, 0).setContent(content.layout.contentWidth - 60, 60);
    62. cntTitle.getLayout().setPadding(0, 0).setBorderWidth(1).setContentMatchParent(30);
    63. cntTitle.setTextContent("标题").setColor(0xff333333).setTextSize(16);
    64. cntTitle.setBox().setBorderColor(0xffcccccc);
    65. cntDesc.getLayout().setPadding(0, 0).setBorderWidth(1).setContentMatchParent(24).setPosition(0, 30);
    66. cntDesc.setTextContent("内容描述").setColor(0xff666666).setTextSize(14);
    67. cntDesc.setBox().setBorderColor(0xffcccccc);
    68. // 动画
    69. sectionAnimate.getLayout().setBorderWidth(1).setPadding(10).setPosition(0, section1.getLayout().getHeight() + section1.getLayout().top + 15).setContentMatchParent(300);
    70. sectionAnimate.setBox().setBackgroundColor(Color.WHITE).setBorderColor(0xffcccccc).setBorderRadius(10);
    71. float width = sectionAnimate.getLayout().getWidth();
    72. float height = sectionAnimate.getLayout().getHeight();
    73. for (int i = 0; i < 500; i++) {
    74. CicleShape cicle = new CicleShape();
    75. sectionAnimate.addChild(cicle);
    76. int color = ((int) (Math.random() * 0xffffff)) | 0xff000000;
    77. cicle.setFill(color);
    78. cicle.setR((float) (30 * Math.random() + 5)).setCenter((float) (width * Math.random()), (float) (height * Math.random()));
    79. cicle.getParams().put("dir", color % 2 == 0 ? 1 : -1);
    80. }
    81. Anime.Instance anime = root.anime.create("{loopCount:0,duration:100,isGoBack:true,easing:'easeInOutQuart',change:null}", null);
    82. anime.change = (double px, Anime.Instance animate, Anime.PropKeyFrame propKeyFrame) -> {
    83. if (sectionAnimate.childs != null) {
    84. for (Element item : sectionAnimate.childs) {
    85. CicleShape cicle = (CicleShape) item;
    86. int dir = (int) cicle.getParams().get("dir");
    87. float cx = cicle.x + dir * (float) (Math.random());
    88. float cy = cicle.y + dir * (float) (Math.random());
    89. if (cx < 0 || cx > width) {
    90. dir = dir * -1;
    91. }
    92. if (cy < 0 || cy > height) {
    93. dir = dir * -1;
    94. }
    95. cicle.getParams().put("dir", dir);
    96. cicle.setCenter(cx, cy);
    97. }
    98. }
    99. root.setUpdateView();
    100. };
    101. anime.restart();
    102. //滚动条
    103. sectionScroll.getLayout().setBorderWidth(1).setPadding(10).setPosition(0, sectionAnimate.getLayout().getHeight() + sectionAnimate.getLayout().top + 15).setContentMatchParent(300);
    104. sectionScroll.setBox().setBackgroundColor(Color.WHITE).setBorderColor(0xffcccccc).setBorderRadius(10);
    105. for (int i = 0; i < 20; i++) {
    106. //@formatter:off
    107. Element item = new Element();
    108. sectionScroll.addChild(item);
    109. Element text = new Element();
    110. item.addChild(text);
    111. //@formatter:on
    112. float itemHeight = 36;
    113. item.getLayout().setPadding(5).setBorderWidth(1).setBoxSize(sectionScroll.layout.contentWidth, itemHeight).setPosition(0, (itemHeight + 5) * i + 5);
    114. item.setBox().setBorderColor(0xffcccccc).setBorderRadius(10);
    115. text.getLayout().setContentMatchParent(14);
    116. text.setTextContent("scroll item" + i).setTextSize(14).setColor(Color.GREEN);
    117. final int idx = i;
    118. item.setSilent(true).getEvent().on(Event.Touchstart, (Event event) -> {
    119. event.current.setBox().setBackgroundColor(0xffe0e0e0);
    120. return false;
    121. }).on(Event.Touchend, (Event event) -> {
    122. event.current.setBox().setBackgroundColor(Color.WHITE);
    123. return false;
    124. }).on(Event.Click, (Event event) -> {
    125. Log.d("click", "item" + idx);
    126. return false;
    127. });
    128. }
    129. sectionScroll.setScroll().updateScrollSize();
    130. }
    131. @Override
    132. protected void onDraw(Canvas canvas) {
    133. super.onDraw(canvas);
    134. long t = System.currentTimeMillis();
    135. root.render(canvas);
    136. long end = System.currentTimeMillis();
    137. //Log.d("onDraw", (end - t) + "ms");
    138. }
    139. @Override
    140. public boolean onTouchEvent(MotionEvent event) {
    141. root.dispatchEvent(event);
    142. return true;
    143. }
    144. @Override
    145. public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    146. setMeasuredDimension(screenWidth, screenHeight);
    147. }
    148. }
    MainActivity.java
    
    1. package com.github.chengxg.object_canvas;
    2. import android.app.Activity;
    3. import android.os.Bundle;
    4. import android.widget.FrameLayout;
    5. public class MainActivity extends Activity {
    6. @Override
    7. protected void onCreate(Bundle savedInstanceState) {
    8. super.onCreate(savedInstanceState);
    9. FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT);
    10. FrameLayout layout = new FrameLayout(this);
    11. CanvasDemoView demoView = new CanvasDemoView(this, null);
    12. demoView.setLayoutParams(layoutParams);
    13. layout.addView(demoView);
    14. this.addContentView(layout, layoutParams);
    15. }
    16. @Override
    17. protected void onStart() {
    18. super.onStart();
    19. }
    20. @Override
    21. protected void onStop() {
    22. super.onStop();
    23. }
    24. @Override
    25. protected void onDestroy() {
    26. super.onDestroy();
    27. }
    28. }

  • 相关阅读:
    研发过程中的文档管理与工具
    CMake中option和cmake_dependent_option的使用
    STM32--ESP8266物联网WIFI模块(贝壳物联)--远程无线控制点灯
    【Android】
    Java8中的 LocalDateTime
    jQuery 语法
    苹果手机自身的ip地址怎么查
    学校介绍静态HTML网页设计作品 DIV布局学校官网模板代码 DW大学网站制作成品下载 HTML5期末大作业
    linux常用指令
    人工智能数学基础--概率与统计10:离散随机变量的概率函数及常见的二项分布、泊松分布
  • 原文地址:https://blog.csdn.net/cxgasd/article/details/128038023