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中。
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截图
文章图片
文章图片
文章图片
文章图片
7. app运行视频(本地模拟器运行)
基于Canvas的MyMathDraw[我的数学板][底部弹窗][API V6]
【harmonyos|HarmonyOS应用开发--基于Canvas的MyMathDraw[我的数学板][底部弹窗][API V6]】
推荐阅读
- 鸿蒙资源文件分类
- harmonyos|HarmonyOS应用开发【项目实践】——专栏介绍(作者(TDTX))
- 鸿蒙|轻松玩转HarmonyOS分布式应用开发——分布式通讯录
- 鸿蒙内核源码分析|v82.01 鸿蒙内核源码分析(协处理器篇) | CPU的好帮手 | 百篇博客分析OpenHarmony源码
- JVM|JAVA中常量池、运行时常量池、字符串常量池区别
- 数据结构|给定值将链表分割成两部分
- JAVA|Java中常量池、运行时常量池和字符串常量池的区别
- Java|Java整合腾讯云短信发送
- LeetCode|LeetCode刷题笔记(279.完全平方数)