使用Java语言开发鸿蒙系统应用的自定义组件五角星,并绘制红旗。
如果对自定义组件并不了解的同学请先看【鸿蒙】HarMonyOS的自定义组件一
我们知道所有的组件都是继承至Component类,我们绘制五角星也不例外,我们先定义一个类继承至Component类,并实现几个构造方法
public class StarsChinaComponentextends Component{
public StarsChinaComponent(Context context) {
super(context);
}
public StarsChinaComponent(Context context, AttrSet attrSet) {
super(context, attrSet);
}
}
?接下来设置自定义组件的宽度和高度,这个设置需要实现Component.EstimateSizeListener接口,并在构造方法中添加宽高改变事件,同时重写onEstimateSize方法
public class StarsChinaComponent extends Component implements
Component.EstimateSizeListener{
public StarsChinaComponent(Context context) {
super(context);
//添加组件大小监听器
setEstimateSizeListener(this);
}
public StarsChinaComponent(Context context, AttrSet attrSet) {
super(context, attrSet);
}
@Override
public boolean onEstimateSize(int i, int i1) {
/*i = (int) (radius * Math.cos(degree2Radian(DEGREE) / 2) * 2);
i1 = (int) (radius + radius
* Math.cos(degree2Radian(DEGREE)));*/
int w = Component.EstimateSpec.getSize(i);
int h = Component.EstimateSpec.getSize(i1);
setEstimatedSize(
//NOT_EXCEED 已为子组件确定了最大大小,子组件不能超过指定大小。
//PRECISE 父组件已确定子组件的大小。
//UNCONSTRAINT 父组件对子组件没有约束,表示子组件可以任意大小。
Component.EstimateSpec.getChildSizeWithMode(w, w, EstimateSpec.NOT_EXCEED),
Component.EstimateSpec.getChildSizeWithMode(h, h, EstimateSpec.NOT_EXCEED)
);
return true;
}
}
接下来初始化画笔参数,设置绘制图形的时候所需要的颜色,线条的宽度,是否需要填充图形等等
public class StarsChinaComponent extends Component implements
Component.EstimateSizeListener{
// 画笔
private Paint paint;
public StarsChinaComponent(Context context) {
super(context);
//添加组件大小监听器
setEstimateSizeListener(this);
//初始化画笔
initPaint();
}
public void initPaint() {
//创建画笔
paint = new Paint();
//设置画笔颜色
paint.setColor(Color.YELLOW);
//设置线条宽度
paint.setStrokeWidth(20);
//设置线条样式
//STROKE_STYLE 空心线条
//FILL_STYLE 实心
//FILLANDSTROKE_STYLE实心和边框线条
paint.setStyle(Paint.Style.FILL_STYLE);
}
public StarsChinaComponent(Context context, AttrSet attrSet) {
super(context, attrSet);
}
@Override
public boolean onEstimateSize(int i, int i1) {
/*i = (int) (radius * Math.cos(degree2Radian(DEGREE) / 2) * 2);
i1 = (int) (radius + radius
* Math.cos(degree2Radian(DEGREE)));*/
int w = Component.EstimateSpec.getSize(i);
int h = Component.EstimateSpec.getSize(i1);
setEstimatedSize(
//NOT_EXCEED 已为子组件确定了最大大小,子组件不能超过指定大小。
//PRECISE 父组件已确定子组件的大小。
//UNCONSTRAINT 父组件对子组件没有约束,表示子组件可以任意大小。
Component.EstimateSpec.getChildSizeWithMode(w, w, EstimateSpec.NOT_EXCEED),
Component.EstimateSpec.getChildSizeWithMode(h, h, EstimateSpec.NOT_EXCEED)
);
return true;
}
}
那么接下来开始绘制五角星,绘制五角星需要分析五角星的绘制过程,我们通过数学的几何图形这么课程可以知道,绘制五角星需要将一个圆平均切为10个圆弧作为五角星的十个连接点,所有我们需要设置圆的半径,圆弧的角度为36°
public class StarsChinaComponent extends Component implements
Component.EstimateSizeListener{
private float radius = 20;//绘制五角星的圆形半径
private int color = 0xFF0000;//默认的颜色
private final static float DEGREE = 36; // 五角星角度
// 画笔
private Paint paint;
public StarsChinaComponent(Context context) {
super(context);
//添加组件大小监听器
setEstimateSizeListener(this);
//初始化画笔
initPaint();
}
public float getRadius() {
return radius;
}
public void setRadius(float radius) {
this.radius = radius;
}
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
}
public void initPaint() {
//创建画笔
paint = new Paint();
//设置画笔颜色
paint.setColor(Color.GRAY);
//设置线条宽度
paint.setStrokeWidth(20);
//设置线条样式
//STROKE_STYLE 空心线条
//FILL_STYLE 实心
//FILLANDSTROKE_STYLE实心和边框线条
paint.setStyle(Paint.Style.FILL_STYLE);
}
public StarsChinaComponent(Context context, AttrSet attrSet) {
super(context, attrSet);
}
@Override
public boolean onEstimateSize(int i, int i1) {
/*i = (int) (radius * Math.cos(degree2Radian(DEGREE) / 2) * 2);
i1 = (int) (radius + radius
* Math.cos(degree2Radian(DEGREE)));*/
int w = Component.EstimateSpec.getSize(i);
int h = Component.EstimateSpec.getSize(i1);
setEstimatedSize(
//NOT_EXCEED 已为子组件确定了最大大小,子组件不能超过指定大小。
//PRECISE 父组件已确定子组件的大小。
//UNCONSTRAINT 父组件对子组件没有约束,表示子组件可以任意大小。
Component.EstimateSpec.getChildSizeWithMode(w, w, EstimateSpec.NOT_EXCEED),
Component.EstimateSpec.getChildSizeWithMode(h, h, EstimateSpec.NOT_EXCEED)
);
return true;
}
}
接下来需要实现Component.DrawTask接口,并重写onDraw方法,通过Canvas绘制图层和图形
public class StarsChinaComponent extends Component implements
Component.EstimateSizeListener, Component.DrawTask,{
private float radius = 20;//绘制五角星的圆形半径
private int color = 0xFF0000;//默认的颜色
private final static float DEGREE = 36; // 五角星角度
// 画笔
private Paint paint;
public StarsChinaComponent(Context context) {
super(context);
//添加组件大小监听器
setEstimateSizeListener(this);
//初始化画笔
initPaint();
// 添加绘制任务
addDrawTask(this);
}
public float getRadius() {
return radius;
}
public void setRadius(float radius) {
this.radius = radius;
}
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
}
public void initPaint() {
//创建画笔
paint = new Paint();
//设置画笔颜色
paint.setColor(Color.GRAY);
//设置线条宽度
paint.setStrokeWidth(20);
//设置线条样式
//STROKE_STYLE 空心线条
//FILL_STYLE 实心
//FILLANDSTROKE_STYLE实心和边框线条
paint.setStyle(Paint.Style.FILL_STYLE);
}
public StarsChinaComponent(Context context, AttrSet attrSet) {
super(context, attrSet);
}
@Override
public boolean onEstimateSize(int i, int i1) {
/*i = (int) (radius * Math.cos(degree2Radian(DEGREE) / 2) * 2);
i1 = (int) (radius + radius
* Math.cos(degree2Radian(DEGREE)));*/
int w = Component.EstimateSpec.getSize(i);
int h = Component.EstimateSpec.getSize(i1);
setEstimatedSize(
//NOT_EXCEED 已为子组件确定了最大大小,子组件不能超过指定大小。
//PRECISE 父组件已确定子组件的大小。
//UNCONSTRAINT 父组件对子组件没有约束,表示子组件可以任意大小。
Component.EstimateSpec.getChildSizeWithMode(w, w, EstimateSpec.NOT_EXCEED),
Component.EstimateSpec.getChildSizeWithMode(h, h, EstimateSpec.NOT_EXCEED)
);
return true;
}
@Override
public void onDraw(Component component, Canvas canvas) {
Path path = new Path();
float radian = degree2Radian(DEGREE);
float radius_in = (float) (radius * Math.sin(radian / 2) / Math
.cos(radian)); // 中间五边形的半径
path.moveTo((float) (radius * Math.cos(radian / 2)), 0);
path.lineTo(
(float) (radius * Math.cos(radian / 2) + radius_in
* Math.sin(radian)),
(float) (radius - radius * Math.sin(radian / 2)));
path.lineTo((float) (radius * Math.cos(radian / 2) * 2),
(float) (radius - radius * Math.sin(radian / 2)));
path.lineTo(
(float) (radius * Math.cos(radian / 2) + radius_in
* Math.cos(radian / 2)), (float) (radius + radius_in
* Math.sin(radian / 2)));
path.lineTo(
(float) (radius * Math.cos(radian / 2) + radius
* Math.sin(radian)),
(float) (radius + radius * Math.cos(radian)));
path.lineTo((float) (radius * Math.cos(radian / 2)),
(float) (radius + radius_in));
path.lineTo(
(float) (radius * Math.cos(radian / 2) - radius
* Math.sin(radian)),
(float) (radius + radius * Math.cos(radian)));
path.lineTo(
(float) (radius * Math.cos(radian / 2) - radius_in
* Math.cos(radian / 2)), (float) (radius + radius_in
* Math.sin(radian / 2)));
path.lineTo(0, (float) (radius - radius * Math.sin(radian / 2)));
path.lineTo(
(float) (radius * Math.cos(radian / 2) - radius_in
* Math.sin(radian)),
(float) (radius - radius * Math.sin(radian / 2)));
path.close();
canvas.drawPath(path, paint);
}
/**
* 角度转弧度
*
* @param degree
* @return
*/
private float degree2Radian(float degree) {
//把一个圆分成五份
return (float) (Math.PI * degree / 180);
}
}
这时候一个五角星就绘制完成了。那么接下来我们需要AbilitySlice类展示组件,然后动态创建一个绝对布局,并设置宽度为填充整个手机屏幕高宽,高度为600,创建五个五角星组件对象,更改五角星的半径来调整五角星的大小,一个大五角星,四个小吴江行,设置其五角星的高宽和绘制半径,以及五角星的大小,并将绘制的五角星添加至现形布局,最后将布局加载至界面进行渲染即可。
package com.example.hm_phone_java.slice;
import com.example.hm_phone_java.views.StarsChinaComponent;
import com.example.hm_phone_java.views.StarsComponent;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.AttrHelper;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.PositionLayout;
import ohos.agp.components.element.ShapeElement;
public class ChinaAbilitySlice extends AbilitySlice {
@Override
protected void onStart(Intent intent) {
super.onStart(intent);
//创建绝对布局
PositionLayout pl=new PositionLayout(this);
//设置绝对布局的宽度填充整个屏幕,高度为600
ComponentContainer.LayoutConfig config=
new ComponentContainer.LayoutConfig(
ComponentContainer.LayoutConfig.MATCH_PARENT,
600);
//将宽高信息设置给绝对布局
pl.setLayoutConfig(config);
//设置背景颜色为红色
ShapeElement element=new ShapeElement();
element.setRgbColor(new RgbColor(255,0,0));
pl.setBackground(element);
//创建大五角星组件对象
StarsChinaComponent component = new StarsChinaComponent(this);
//设置五角星显示在绝对布局的哪个位置
component.setPosition(vp2px(20),vp2px(35));
//设置五角星的绘制半径
component.setRadius(100);
//设置五角星的高宽
DirectionalLayout.LayoutConfig lc=new DirectionalLayout.LayoutConfig(200,200);
lc.setMargins(10,10,10,10);
//将参数添加至五角星组件对象
component.setLayoutConfig(lc);
//将五角星添加至线性布局
pl.addComponent(component);
//创建小五角星组件对象
StarsChinaComponent component1 = new StarsChinaComponent(this);
//设置五角星显示在绝对布局的哪个位置
component1.setPosition(vp2px(95),vp2px(10));
//设置五角星的绘制半径
component1.setRadius(40);
//将参数添加至五角星组件对象
component1.setLayoutConfig(lc);
//将五角星添加至线性布局
pl.addComponent(component1);
//创建小五角星组件对象
StarsChinaComponent component2 = new StarsChinaComponent(this);
//设置五角星显示在绝对布局的哪个位置
component2.setPosition(vp2px(120),vp2px(35));
//设置五角星的绘制半径
component2.setRadius(40);
//将参数添加至五角星组件对象
component2.setLayoutConfig(lc);
//将五角星添加至线性布局
pl.addComponent(component2);
//创建小五角星组件对象
StarsChinaComponent component3 = new StarsChinaComponent(this);
//设置五角星显示在绝对布局的哪个位置
component3.setPosition(vp2px(120),vp2px(75));
//设置五角星的绘制半径
component3.setRadius(40);
//将参数添加至五角星组件对象
component3.setLayoutConfig(lc);
//将五角星添加至线性布局
pl.addComponent(component3);
//创建小五角星组件对象
StarsChinaComponent component4 = new StarsChinaComponent(this);
//设置五角星显示在绝对布局的哪个位置
component4.setPosition(vp2px(95),vp2px(100));
//设置五角星的绘制半径
component4.setRadius(40);
//将参数添加至五角星组件对象
component4.setLayoutConfig(lc);
//将五角星添加至线性布局
pl.addComponent(component4);
//将线性布局加载至界面显示
super.setUIContent(pl);
}
/**
* 单位转换的方法
* @param vp
* @return
*/
private int vp2px(float vp){
return AttrHelper.vp2px(vp,this);
}
}
将该ChinaAbilitySlice添加至主界面中
package com.example.hm_phone_java;
import com.example.hm_phone_java.slice.*;
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(ChinaAbilitySlice.class.getName());
}
}
最后启动华为模拟器,即可看到效果。
|