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

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图标:

在这里插入图片描述

2. 功能描述

  • 具有一个底部弹窗,可以在弹出的设置小窗口中进行设置。
  • 具有绘制函数的功能,输入数学函数,点击表情,即可在TextField中绘制图像。

在这里插入图片描述

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<float[]> 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<float[]> 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<float[]> 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

<shape xmlns:ohos="http://schemas.huawei.com/res/ohos"ohos:shape="rectangle">    <corners ohos:radius="20vp"/>    <solid ohos:color="#B2F1EDED"/></shape>

    4.2.2 background_ability_main.xml

<shape xmlns:ohos="http://schemas.huawei.com/res/ohos"ohos:shape="rectangle">    <solid ohos:color="#FFFFFF"/></shape>

  4.3 主页面XML代码

    4.3.1 ability_main.xml

<DirectionalLayout    xmlns:ohos="http://schemas.huawei.com/res/ohos"    ohos:id="$+id:mymathdraw_rootdl"    ohos:height="match_parent"    ohos:width="match_parent"    ohos:alignment="center"    ohos:orientation="vertical">    <StackLayout ohos:id="$+id:rootdl_stkl" ohos:height="match_parent" ohos:width="match_parent"> <DirectionalLayout     ohos:id="$+id:rootdl_stkl_ddl1"     ohos:height="match_parent"     ohos:width="match_parent"     ohos:alignment="center"     ohos:orientation="vertical"     ohos:background_element="white">     <DirectionalLayout  ohos:id="$+id:rootdl_stkl_ddl1_topdl"  ohos:height="0"  ohos:weight="0.7"  ohos:width="match_parent"  ohos:alignment="center"  ohos:orientation="horizontal"  ohos:background_element="#70B3ECF3">  <Text      ohos:id="$+id:topdl_txt"      ohos:height="match_parent"      ohos:width="0"      ohos:weight="8"      ohos:text="MathPad"      ohos:text_size="35vp"      ohos:text_color="#FF2DDE53"      ohos:text_alignment="vertical_center"      >  </Text>  <Button      ohos:id="$+id:topdl_but"      ohos:height="match_parent"      ohos:width="0"      ohos:weight="2"      ohos:text="😁"      ohos:text_size="30vp"      ohos:text_alignment="center"      ohos:background_element="#9FA9EFE5">  </Button>     </DirectionalLayout>     <DirectionalLayout  ohos:id="$+id:rootdl_stkl_ddl1_bottomdl"  ohos:height="0"  ohos:weight="9.3"  ohos:width="match_parent"  ohos:alignment="center"  ohos:orientation="vertical"  ohos:background_element="#FFFFFFFF">  <TextField      ohos:id="$+id:bottomdl_tfd"      ohos:height="match_parent"      ohos:width="match_parent"      ohos:hint="输入函数>>>"      ohos:text_size="25vp"      ohos:text_alignment="start"      ohos:background_element="#FFFFFFFF">  </TextField>     </DirectionalLayout> </DirectionalLayout> <DirectionalLayout     ohos:id="$+id:rootdl_stkl_ddl2"     ohos:height="match_parent"     ohos:width="match_parent"     ohos:visibility="hide"     ohos:alignment="bottom"     ohos:orientation="vertical"     ohos:background_element="#00FFFFFF">     <DirectionalLayout  ohos:id="$+id:rootdl_stkl_ddl2_set"  ohos:height="220vp"  ohos:width="300vp"  ohos:bottom_margin="20vp"  ohos:layout_alignment="center"  ohos:background_element="$graphic:background_ability_ddl2_set"  ohos:orientation="vertical"  ohos:alignment="center">  <DirectionalLayout      ohos:height="0"      ohos:weight="1"      ohos:width="match_parent"      ohos:alignment="bottom"      ohos:orientation="horizontal">      <Text   ohos:id="$+id:paintswitch_text"   ohos:height="30vp"   ohos:width="0"   ohos:weight="1"   ohos:text_alignment="center"   ohos:auto_font_size="true"   ohos:text="画笔:蓝色"   ohos:text_color="blue"   >      </Text>      <Text   ohos:id="$+id:uiswitch_text"   ohos:height="30vp"   ohos:width="0"   ohos:weight="1"   ohos:text_alignment="center"   ohos:auto_font_size="true"   ohos:text="界面:明亮"   ohos:text_color="#FFEE6363"   >      </Text>  </DirectionalLayout>  <DirectionalLayout      ohos:height="0"      ohos:weight="1"      ohos:width="match_parent"      ohos:alignment="center"      ohos:orientation="horizontal">      <Switch   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"   >      </Switch>      <Switch   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"   >      </Switch>  </DirectionalLayout>     </DirectionalLayout> </DirectionalLayout>    </StackLayout></DirectionalLayout>

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#section1112183053510ohos {    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截图

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

7. app运行视频(本地模拟器运行)

基于Canvas的MyMathDraw[我的数学板][底部弹窗][API V6]