harmonyos|HarmonyOS应用开发--基于Canvas的MyMathDraw[我的数学板][底部弹窗][API V6]


HarmonyOS应用开发--基于Canvas的MyMathDraw[我的数学板][底部弹窗][API V6]

  • 1. 名称
  • 2. 功能描述
  • 3. app实现关键技巧
  • 4. 源代码
    • 4.1 java源代码
      • 4.1.1 MainAbilitySlice.java
      • 4.1.2 MainAbility.java
      • 4.1.3 MyApplication.java
    • 4.2 UI背景XML代码
      • 4.2.1 background_ability_ddl2_set.xml
      • 4.2.2 background_ability_main.xml
    • 4.3 主页面XML代码
      • 4.3.1 ability_main.xml
  • 5. build.gradle(Entry模块中的)
  • 6. app截图
  • 7. app运行视频(本地模拟器运行)

1. 名称
  • 本次使用Canvas实现了一个绘制数学函数的app,命名为:我的数学板,MyMathDraw。
  • 项目采用了parsii-4.0库,特此声明。
  • 项目已经放置在Gitee仓库中:MyMathDraw。
  • 本专栏关于使用开发语言的声明:全专栏专注于Java语言开发模式!
  • app图标:
harmonyos|HarmonyOS应用开发--基于Canvas的MyMathDraw[我的数学板][底部弹窗][API V6]
文章图片

2. 功能描述
  • 具有一个底部弹窗,可以在弹出的设置小窗口中进行设置。
  • 具有绘制函数的功能,输入数学函数,点击表情,即可在TextField中绘制图像。
harmonyos|HarmonyOS应用开发--基于Canvas的MyMathDraw[我的数学板][底部弹窗][API V6]
文章图片

3. app实现关键技巧
  • 实现底部弹窗:本次app使用了StackLayout,最底层放置绘制的界面,最上层放置弹窗界面,其中弹窗界面上部分是灰色透明,下部分是圆角长方形弹窗,用于设置。默认情况,将其设置为HIDE即可,当用户点击左上角文字时,设置为VISIBLE,即可达到“弹窗”功能。
  • 实现函数绘制:采用描点法绘制函数,密集的描点即可。其中对函数表达式采用parsii库提供的表达式解析功能,生成每个x对应的y值,放入ArrayList中。
4. 源代码 4.1 java源代码 4.1.1 MainAbilitySlice.java
package com.tdtxdcxm.mymathdraw.slice; import com.tdtxdcxm.mymathdraw.ResourceTable; import ohos.aafwk.ability.AbilitySlice; import ohos.aafwk.content.Intent; import ohos.agp.colors.RgbColor; import ohos.agp.components.*; import ohos.agp.components.element.ShapeElement; import ohos.agp.render.Canvas; import ohos.agp.render.Paint; import ohos.agp.utils.Color; import parsii.eval.Expression; import parsii.eval.Parser; import parsii.eval.Scope; import parsii.eval.Variable; import parsii.tokenizer.ParseException; import java.util.ArrayList; public class MainAbilitySlice extends AbilitySlice {DirectionalLayout rootdl_stkl_ddl2,rootdl_stkl_ddl2_set; Button topdl_but; TextField bottomdl_tfd; Text topdl_txt,paintswitch_text,uiswitch_text; Switch switch_paintcolor,switch_uicolor; Paint bluepaint = new Paint(); Paint purplepaint = new Paint(); Paint paint = bluepaint; //用于绘制任务的默认画笔(蓝色) int origin_x,origin_y; boolean isgeneratexy = false; public void initPaint(){ bluepaint.setColor(Color.BLUE); bluepaint.setStrokeWidth(8); purplepaint.setColor(new Color(Color.rgb(160, 32, 240))); purplepaint.setStrokeWidth(8); }public void initMASComponents(){ topdl_txt = (Text) findComponentById(ResourceTable.Id_topdl_txt); topdl_but = (Button) findComponentById(ResourceTable.Id_topdl_but); bottomdl_tfd = (TextField) findComponentById(ResourceTable.Id_bottomdl_tfd); rootdl_stkl_ddl2 = (DirectionalLayout) findComponentById(ResourceTable.Id_rootdl_stkl_ddl2); rootdl_stkl_ddl2_set = (DirectionalLayout) findComponentById(ResourceTable.Id_rootdl_stkl_ddl2_set); paintswitch_text = (Text) findComponentById(ResourceTable.Id_paintswitch_text); uiswitch_text = (Text) findComponentById(ResourceTable.Id_uiswitch_text); switch_paintcolor = (Switch) findComponentById(ResourceTable.Id_switch_paintcolor); switch_uicolor = (Switch) findComponentById(ResourceTable.Id_switch_uicolor); bottomdl_tfd.setHint("输入函数>>>"+"\n【右上角表情】:\n1.单击—绘制"+"\n2.长按-清空"); topdl_txt.setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { bottomdl_tfd.clearFocus(); rootdl_stkl_ddl2.setVisibility(Component.VISIBLE); if(topdl_but.getText().equals("")){ topdl_but.setText(""); } } }); topdl_but.setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { bottomdl_tfd.clearFocus(); String function = bottomdl_tfd.getText(); ArrayList xylist = generateXY(function); //根据表达式生成许多x、y点坐标 if(xylist == null){ return; } bottomdl_tfd.addDrawTask(new Component.DrawTask() { @Override public void onDraw(Component component, Canvas canvas) { if(isgeneratexy) { for (float[] xyfloats : xylist) { canvas.drawPoint(xyfloats[0], xyfloats[1], paint); } } } }, Component.DrawTask.BETWEEN_BACKGROUND_AND_CONTENT); } }); topdl_but.setLongClickedListener(new Component.LongClickedListener() { @Override public void onLongClicked(Component component) { bottomdl_tfd.setText(""); bottomdl_tfd.clearFocus(); bottomdl_tfd.addDrawTask(new Component.DrawTask() { @Override public void onDraw(Component component, Canvas canvas) { //用于清空,画一个空白 } }, Component.DrawTask.BETWEEN_BACKGROUND_AND_CONTENT); } }); rootdl_stkl_ddl2.setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { //弹出设置面板后,单击其余区域会退出(收回)设置状态 rootdl_stkl_ddl2.setVisibility(Component.HIDE); topdl_but.setText(""); } }); rootdl_stkl_ddl2_set.setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { //这里用来“吸收”单击事件,否则当单击设置面板时,也会退出设置状态 } }); switch_paintcolor.setCheckedStateChangedListener(new AbsButton.CheckedStateChangedListener() { @Override public void onCheckedChanged(AbsButton absButton, boolean b) { if(b == true){ paint = purplepaint; //把紫色画笔给绘制任务画笔 paintswitch_text.setText("画笔:紫色"); paintswitch_text.setTextColor(new Color(Color.rgb(160, 32, 240))); } else{ paint = bluepaint; //把蓝色画笔给绘制任务画笔,还原默认 paintswitch_text.setText("画笔:蓝色"); paintswitch_text.setTextColor(Color.BLUE); } } }); switch_uicolor.setCheckedStateChangedListener(new AbsButton.CheckedStateChangedListener() { @Override public void onCheckedChanged(AbsButton absButton, boolean b) { if(b == true){ uiswitch_text.setText("界面:黑暗"); uiswitch_text.setTextColor(new Color(Color.rgb(54, 54, 54))); ShapeElement shape = new ShapeElement(); shape.setRgbColor(new RgbColor(105,105,105)); bottomdl_tfd.setBackground(shape); } else{ uiswitch_text.setText("界面:明亮"); uiswitch_text.setTextColor(new Color(Color.rgb(238, 99, 99))); ShapeElement shape = new ShapeElement(); shape.setRgbColor(new RgbColor(255,255,255)); bottomdl_tfd.setBackground(shape); } } }); }public ArrayList generateXY(String function){ if(function.equals("")){ return null; } origin_x = bottomdl_tfd.getWidth() / 2; //将绘图坐标远点的x设定在此 origin_y = bottomdl_tfd.getHeight() / 2; //将绘图坐标远点的y设定在此 System.out.println(origin_x); System.out.println(origin_y); ArrayList xylist = new ArrayList<>(); StringBuilder stringBuilder = new StringBuilder(function); Scope scope = new Scope(); Variable var_x = scope.getVariable("x"); Expression expression = null; try { expression = Parser.parse(function, scope); } catch (ParseException e) { e.printStackTrace(); } if(expression == null){ return null; }for(float x = -400f; x <= 400.0f; x = x + 0.001f){ var_x.setValue((double) x); double y = expression.evaluate(); //将图形默认放大 float[] xyfloats = {x*140+origin_x,-140*((float) y)+origin_y}; xylist.add(xyfloats); } isgeneratexy = true; return xylist; }@Override public void onStart(Intent intent) { super.onStart(intent); super.setUIContent(ResourceTable.Layout_ability_main); initPaint(); initMASComponents(); }@Override public void onInactive() { super.onInactive(); }@Override public void onActive() { super.onActive(); }@Override public void onForeground(Intent intent) { super.onForeground(intent); }@Override public void onBackground() { super.onBackground(); }@Override public void onStop() { super.onStop(); } }

4.1.2 MainAbility.java
package com.tdtxdcxm.mymathdraw; import com.tdtxdcxm.mymathdraw.slice.MainAbilitySlice; import ohos.aafwk.ability.Ability; import ohos.aafwk.content.Intent; public class MainAbility extends Ability { @Override public void onStart(Intent intent) { super.onStart(intent); super.setMainRoute(MainAbilitySlice.class.getName()); } }

4.1.3 MyApplication.java
package com.tdtxdcxm.mymathdraw; import ohos.aafwk.ability.AbilityPackage; public class MyApplication extends AbilityPackage { @Override public void onInitialize() { super.onInitialize(); } }

4.2 UI背景XML代码 4.2.1 background_ability_ddl2_set.xml
xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:shape="rectangle"> ohos:color="#B2F1EDED"/>

4.2.2 background_ability_main.xml
xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:shape="rectangle"> ohos:color="#FFFFFF"/>

4.3 主页面XML代码 4.3.1 ability_main.xml
ohos:id="$+id:rootdl_stkl" ohos:height="match_parent" ohos:width="match_parent"> ohos:id="$+id:switch_paintcolor" ohos:height="25vp" ohos:width="90vp"ohos:right_margin="30vp"ohos:auto_font_size="true"ohos:text_state_on="紫色" ohos:text_color_on="red"ohos:text_state_off="蓝色" ohos:text_color_off="black" > ohos:id="$+id:switch_uicolor" ohos:height="25vp" ohos:width="90vp"ohos:left_margin="30vp"ohos:auto_font_size="true"ohos:text_state_on="黑暗" ohos:text_color_on="red"ohos:text_state_off="明亮" ohos:text_color_off="black" >

5. build.gradle(Entry模块中的)
apply plugin: 'com.huawei.ohos.hap' apply plugin: 'com.huawei.ohos.decctest' //For instructions on signature configuration, see https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ide_debug_device-0000001053822404#section1112183053510 ohos { compileSdkVersion 6 defaultConfig { compatibleSdkVersion 6 } buildTypes { release { proguardOpt { proguardEnabled false rulesFiles 'proguard-rules.pro' } } } }dependencies { implementation fileTree(dir: 'libs', include: ['*.jar', '*.har']) testImplementation 'junit:junit:4.13.1' ohosTestImplementation 'com.huawei.ohos.testkit:runner:2.0.0.200' implementation 'com.scireum:parsii:4.0' } decc { supportType = ['html', 'xml'] }

6. app截图 harmonyos|HarmonyOS应用开发--基于Canvas的MyMathDraw[我的数学板][底部弹窗][API V6]
文章图片

harmonyos|HarmonyOS应用开发--基于Canvas的MyMathDraw[我的数学板][底部弹窗][API V6]
文章图片

harmonyos|HarmonyOS应用开发--基于Canvas的MyMathDraw[我的数学板][底部弹窗][API V6]
文章图片

harmonyos|HarmonyOS应用开发--基于Canvas的MyMathDraw[我的数学板][底部弹窗][API V6]
文章图片

7. app运行视频(本地模拟器运行)
基于Canvas的MyMathDraw[我的数学板][底部弹窗][API V6]
【harmonyos|HarmonyOS应用开发--基于Canvas的MyMathDraw[我的数学板][底部弹窗][API V6]】

    推荐阅读