鸿蒙HarMonyOS的自定义组件之五星好评
Posted 笔触狂放
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了鸿蒙HarMonyOS的自定义组件之五星好评相关的知识,希望对你有一定的参考价值。
使用Java语言开发鸿蒙系统应用的自定义组件五角星,并实现五星好评的效果。
如果对自定义组件并不了解的同学请先看【鸿蒙】HarMonyOS的自定义组件一
我们知道所有的组件都是继承至Component类,我们绘制五角星也不例外,我们先定义一个类继承至Component类,并实现几个构造方法
public class StarsComponent extends Component{
public StarsComponent(Context context) {
super(context);
}
public StarsComponent(Context context, AttrSet attrSet) {
super(context, attrSet);
}
}
接下来设置自定义组件的宽度和高度,这个设置需要实现Component.EstimateSizeListener接口,并在构造方法中添加宽高改变事件,同时重写onEstimateSize方法
public class StarsComponent extends Component implements
Component.EstimateSizeListener{
public StarsComponent(Context context) {
super(context);
//添加组件大小监听器
setEstimateSizeListener(this);
}
public StarsComponent(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 StarsComponent extends Component implements
Component.EstimateSizeListener{
// 画笔
private Paint paint;
public StarsComponent(Context context) {
super(context);
//添加组件大小监听器
setEstimateSizeListener(this);
//初始化画笔
initPaint();
}
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 StarsComponent(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 StarsComponent extends Component implements
Component.EstimateSizeListener{
private float radius = 20;//绘制五角星的圆形半径
private int color = 0xFF0000;//默认的颜色
private final static float DEGREE = 36; // 五角星角度
// 画笔
private Paint paint;
public StarsComponent(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 StarsComponent(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 StarsComponent 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 StarsComponent(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 StarsComponent(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);
}
}
这时候一个五角星就绘制完成了,那么接下来给该五角星添加触摸事件,当该五角星被第一次点击之后被点亮为红色,第二次点击将该五角星变为灰色。该类实现Component.TouchEventListener接口,并重写onTouchEvent方法
public class StarsComponent extends Component implements
Component.EstimateSizeListener, Component.DrawTask,Component.TouchEventListener{
private float radius = 20;//绘制五角星的圆形半径
private int color = 0xFF0000;//默认的颜色
private final static float DEGREE = 36; // 五角星角度
// 画笔
private Paint paint;
public StarsComponent(Context context) {
super(context);
//添加组件大小监听器
setEstimateSizeListener(this);
//初始化画笔
initPaint();
// 添加绘制任务
addDrawTask(this);
//添加触摸事件
setTouchEventListener(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 StarsComponent(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);
}
private int count=0;
@Override
public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
count++;
//当手指触摸到该五角星时,改变颜色为红色,并刷新图层
if (touchEvent.getAction()==TouchEvent.PRIMARY_POINT_DOWN){
//判断点击的次数,奇数次点亮,偶数次不点亮
if (count%2==1)paint.setColor(Color.RED);
else paint.setColor(Color.GRAY);
invalidate();
}
new ToastDialog(this.getContext()).setText("你的评价是我前进的动力").show();
return false;
}
}
这时候这个自定义的五角星就完成了,那么接下来我们需要AbilitySlice类展示组件,然后动态创建一个线性布局,并设置宽度和高度为填充整个手机屏幕高宽,设置布局摆放顺序为横向摆放。然后循环遍历五次,创建五个五角星组件对象,设置其五角星的高宽和绘制半径,以及五角星的大小,并将绘制的五角星添加至现形布局,最后将布局加载至界面进行渲染即可。
package com.example.hm_phone_java.slice;
import com.example.hm_phone_java.views.CustomComponent;
import com.example.hm_phone_java.views.StarsComponent;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.element.ShapeElement;
public class StarsAbilitySlice extends AbilitySlice {
@Override
protected void onStart(Intent intent) {
super.onStart(intent);
//创建线性布局
DirectionalLayout myLayout=new DirectionalLayout(this);
//设置布局方向为横向对齐
myLayout.setOrientation(DirectionalLayout.HORIZONTAL);
//设置线性布局高宽
DirectionalLayout.LayoutConfig config = new DirectionalLayout.LayoutConfig(
DirectionalLayout.LayoutConfig.MATCH_PARENT, DirectionalLayout.LayoutConfig.MATCH_PARENT);
//将设置的布局参数添加至线性布局对象
myLayout.setLayoutConfig(config);
for (int i = 0; i < 5; i++) {
//创建五角星组件对象
StarsComponent component = new StarsComponent(this);
//设置五角星的绘制半径
component.setRadius(80);
//设置五角星的高宽
DirectionalLayout.LayoutConfig lc=new DirectionalLayout.LayoutConfig(200,200);
lc.setMargins(10,10,10,10);
//将参数添加至五角星组件对象
component.setLayoutConfig(lc);
//将五角星添加至线性布局
myLayout.addComponent(component);
}
//将线性布局加载至界面显示
super.setUIContent(myLayout);
}
}
将该StarsAbilitySlice添加至主界面中
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(StarsAbilitySlice.class.getName());
}
}
最后启动华为模拟器,即可看到效果。
以上是关于鸿蒙HarMonyOS的自定义组件之五星好评的主要内容,如果未能解决你的问题,请参考以下文章