|
|
@@ -0,0 +1,317 @@
|
|
|
+import { YTAvoid, YTHeader } from 'basic'
|
|
|
+import { Cell, Sector } from '../utils/Sector';
|
|
|
+import { CounterComponent, CounterType } from '@kit.ArkUI';
|
|
|
+
|
|
|
+
|
|
|
+@Builder
|
|
|
+function BigWheelViewBuilder(){
|
|
|
+ NavDestination(){
|
|
|
+ BigWheelView()
|
|
|
+ }.title("大转盘")
|
|
|
+ .hideTitleBar(true)
|
|
|
+}
|
|
|
+
|
|
|
+@Component
|
|
|
+struct BigWheelView{
|
|
|
+ @StorageProp(YTAvoid.SAFE_TOP_KEY) safeBottom: number = 0
|
|
|
+
|
|
|
+ @State cells: Cell[] = []; // 存储单元格的数组
|
|
|
+ @State wheelWidth: number = 600; // 转盘的宽度
|
|
|
+ @State currentAngle: number = 0; // 当前转盘的角度
|
|
|
+ @State selectedName: string = ""; // 选中的名称
|
|
|
+ @State isRepeat:boolean=false
|
|
|
+ @Watch('xxx')
|
|
|
+ @State selected:Cell[]=[]
|
|
|
+ @State UnSelected:Cell[]=[]
|
|
|
+ @State randomAngle:number=0
|
|
|
+ isAnimating: boolean = false; // 动画状态
|
|
|
+ colorIndex: number = 0; // 颜色索引
|
|
|
+ spinDuration:number=5000
|
|
|
+
|
|
|
+ colorPalette: string[] = [ // 颜色调色板
|
|
|
+ "#26c2ff",
|
|
|
+ "#978efe",
|
|
|
+ "#c389fe",
|
|
|
+ "#ff85bd",
|
|
|
+ "#ff7051",
|
|
|
+ "#fea800",
|
|
|
+ "#ffcf18",
|
|
|
+ "#a9c92a",
|
|
|
+ "#fea800",
|
|
|
+ "#ffcf18",
|
|
|
+ "#a9c92a"
|
|
|
+ ];
|
|
|
+ xxx(){
|
|
|
+ //每次选中的数组有变化,那就要重新过滤
|
|
|
+ this.UnSelected = this.cells.filter(item =>
|
|
|
+ !this.selected.some(selected => selected.id === item.id));
|
|
|
+ // promptAction.showToast({
|
|
|
+ // message:JSON.stringify(this.UnSelected)
|
|
|
+ // })
|
|
|
+ //要把选的变成灰色
|
|
|
+ // this.cells.map((item)=>{
|
|
|
+ //
|
|
|
+ // })
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // 组件即将出现时调用
|
|
|
+ aboutToAppear(): void {
|
|
|
+ // 初始化单元格
|
|
|
+ this.cells.push(new Cell(1,1, "转盘1", this.colorPalette[this.colorIndex++ % this.colorPalette.length]));
|
|
|
+ this.cells.push(new Cell(2,2, "转盘2", this.colorPalette[this.colorIndex++ % this.colorPalette.length]));
|
|
|
+ this.cells.push(new Cell(3,1, "转盘3", this.colorPalette[this.colorIndex++ % this.colorPalette.length]));
|
|
|
+ this.cells.push(new Cell(4,4, "转盘4", this.colorPalette[this.colorIndex++ % this.colorPalette.length]));
|
|
|
+ this.UnSelected=this.cells
|
|
|
+
|
|
|
+ this.calculateAngles(); // 计算角度
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算每个单元格的角度
|
|
|
+ private calculateAngles() {
|
|
|
+ // 根据比例计算总比例
|
|
|
+ const totalProportion = this.cells.reduce((sum, cell) => sum + cell.proportion, 0);
|
|
|
+ this.cells.forEach(cell => {
|
|
|
+ cell.angle = (cell.proportion * 360) / totalProportion; // 计算每个单元格的角度
|
|
|
+ });
|
|
|
+
|
|
|
+ let cumulativeAngle = 0; // 累计角度
|
|
|
+ this.cells.forEach(cell => {
|
|
|
+ cell.angleStart = cumulativeAngle; // 设置起始角度
|
|
|
+ cumulativeAngle += cell.angle; // 更新累计角度
|
|
|
+ cell.angleEnd = cumulativeAngle; // 设置结束角度
|
|
|
+ cell.rotate = cumulativeAngle - (cell.angle / 2); // 计算旋转角度
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ private calculateNoSelectedAngles(){
|
|
|
+ //在这里计算
|
|
|
+
|
|
|
+ if(this.UnSelected.length!=0) {
|
|
|
+ //随机选取一个没有选中的角度范围扇形
|
|
|
+ const currangle=this.currentAngle%360
|
|
|
+ const randomIndex = Math.floor(Math.random() * this.UnSelected.length) as number
|
|
|
+ const ranNumStart = 360-this.UnSelected[randomIndex].angleEnd
|
|
|
+ const ranNumEnd = 360-this.UnSelected[randomIndex].angleStart
|
|
|
+ this.randomAngle =Math.floor(Math.random() * (ranNumEnd - ranNumStart) + ranNumStart)-currangle
|
|
|
+ }
|
|
|
+ // else{
|
|
|
+ // this.randomAngle=Math.floor(Math.random()*360)
|
|
|
+ // }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ build() {
|
|
|
+ Column() {
|
|
|
+ YTHeader({ title: '大转盘' })
|
|
|
+
|
|
|
+ Row() {
|
|
|
+ Text('转盘').fontSize(20).fontColor("#0b0e15"); // 显示转盘标题
|
|
|
+ }.width('100%').height(44).justifyContent(FlexAlign.Center); // 设置行的宽度和高度
|
|
|
+
|
|
|
+ // 显示当前状态
|
|
|
+ Text(this.isAnimating ? '旋转中' : `${this.selectedName}`).fontSize(20).fontColor("#0b0e15").height(40);
|
|
|
+
|
|
|
+ Stack() {
|
|
|
+ Stack() {
|
|
|
+ // 遍历每个单元格并绘制扇形
|
|
|
+ ForEach(this.cells, (cell: Cell) => {
|
|
|
+ Stack() {
|
|
|
+ Sector({ radius: lpx2px(this.wheelWidth) / 2, angle: cell.angle, color: cell.color }); // 创建扇形
|
|
|
+ Text(cell.title).fontColor(Color.White).margin({ bottom: `${this.wheelWidth / 1.4}lpx` }); // 显示单元格标题
|
|
|
+ }.width('100%').height('100%').rotate({ angle: cell.rotate }); // 设置宽度和高度,并旋转
|
|
|
+ });
|
|
|
+ }
|
|
|
+ .borderRadius('50%') // 设置圆角
|
|
|
+ .backgroundColor(Color.Gray) // 设置背景颜色
|
|
|
+ .width(`${this.wheelWidth}lpx`) // 设置转盘宽度
|
|
|
+ .height(`${this.wheelWidth}lpx`) // 设置转盘高度
|
|
|
+ .rotate({ angle: this.currentAngle }); // 旋转转盘
|
|
|
+
|
|
|
+ // 创建指针
|
|
|
+ Polygon({ width: 20, height: 10 })
|
|
|
+ .points([[0, 0], [10, -20], [20, 0]]) // 设置指针的点
|
|
|
+ .fill("#d72b0b") // 设置指针颜色
|
|
|
+ .height(20) // 设置指针高度
|
|
|
+ .margin({ bottom: '140lpx' }); // 设置指针底部边距
|
|
|
+
|
|
|
+ // 创建开始按钮
|
|
|
+ Button('开始')
|
|
|
+ .fontColor("#c53a2c") // 设置按钮字体颜色
|
|
|
+ .borderWidth(10) // 设置按钮边框宽度
|
|
|
+ .borderColor("#dd2218") // 设置按钮边框颜色
|
|
|
+ .backgroundColor("#fde427") // 设置按钮背景颜色
|
|
|
+ .width('200lpx') // 设置按钮宽度
|
|
|
+ .height('200lpx') // 设置按钮高度
|
|
|
+ .borderRadius('50%') // 设置按钮为圆形
|
|
|
+ .clickEffect({ level: ClickEffectLevel.LIGHT }) // 设置点击效果
|
|
|
+ .onClick(() => { // 点击按钮时的回调函数
|
|
|
+ if (this.isAnimating) { // 如果正在动画中,返回
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if(this.selected.length==this.cells.length){
|
|
|
+ return
|
|
|
+ }
|
|
|
+ //如果都已经被选了,则不能再转了
|
|
|
+ this.calculateNoSelectedAngles()
|
|
|
+ this.selectedName = ""; // 清空选中的名称
|
|
|
+ this.isAnimating = true; // 设置动画状态为正在动画
|
|
|
+ animateTo({ // 开始动画
|
|
|
+ duration: this.spinDuration, // 动画持续时间为5000毫秒
|
|
|
+ curve: Curve.EaseInOut, // 动画曲线为缓入缓出
|
|
|
+ onFinish: () => { // 动画完成后的回调
|
|
|
+ this.currentAngle %= 360; // 保持当前角度在0到360之间
|
|
|
+ for (const cell of this.cells) { // 遍历每个单元格
|
|
|
+ // 检查当前角度是否在单元格的角度范围内
|
|
|
+ if (360 - this.currentAngle >= cell.angleStart && 360 - this.currentAngle <= cell.angleEnd) {
|
|
|
+ this.selected.push(cell)
|
|
|
+ //这里需要下次点击的时候
|
|
|
+ cell.color='#202020'
|
|
|
+ this.selectedName = cell.title; // 设置选中的名称为当前单元格的标题
|
|
|
+ break; // 找到后退出循环
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.isAnimating = false; // 设置动画状态为未动画
|
|
|
+ },
|
|
|
+ }, () => { // 动画进行中的回调
|
|
|
+ //在这里判断
|
|
|
+ // this.randomAngle=Math.floor(Math.random()*360)
|
|
|
+ // this.currentAngle += (360 * this.spinDuration/1000 + Math.floor(Math.random() * 360)); // 更新当前角度,增加随机旋转
|
|
|
+ //在这里算已经选过的,不能在指了
|
|
|
+
|
|
|
+ // this.currentAngle += (360 * this.spinDuration/1000 + Math.floor(Math.random() * 360)); // 更新当前角度,增加随机旋转
|
|
|
+
|
|
|
+ // promptAction.showToast({
|
|
|
+ // message:this.randomAngle.toString()
|
|
|
+ // })
|
|
|
+ this.currentAngle += (360 * this.spinDuration/1000)+this.randomAngle
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建滚动区域
|
|
|
+ Scroll() {
|
|
|
+ Column() {
|
|
|
+ // 遍历每个单元格,创建输入框和计数器
|
|
|
+ ForEach(this.cells, (item: Cell, index: number) => {
|
|
|
+ Row() {
|
|
|
+ // 创建文本输入框,显示单元格标题
|
|
|
+ TextInput({ text: item.title })
|
|
|
+ .layoutWeight(1) // 设置输入框占据剩余空间
|
|
|
+ .onChange((value) => { // 输入框内容变化时的回调
|
|
|
+ item.title = value; // 更新单元格标题
|
|
|
+ });
|
|
|
+ // 创建计数器组件
|
|
|
+ CounterComponent({
|
|
|
+ options: {
|
|
|
+ type: CounterType.COMPACT, // 设置计数器类型为紧凑型
|
|
|
+ numberOptions: {
|
|
|
+ label: `当前占比`, // 设置计数器标签
|
|
|
+ value: item.proportion, // 设置计数器初始值
|
|
|
+ min: 1, // 设置最小值
|
|
|
+ max: 100, // 设置最大值
|
|
|
+ step: 1, // 设置步长
|
|
|
+ onChange: (value: number) => { // 计数器值变化时的回调
|
|
|
+ item.proportion = value; // 更新单元格的比例
|
|
|
+ this.calculateAngles(); // 重新计算角度
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ // 创建删除按钮
|
|
|
+ Button('删除').onClick(() => {
|
|
|
+ this.cells.splice(index, 1); // 从单元格数组中删除当前单元格
|
|
|
+ this.calculateAngles(); // 重新计算角度
|
|
|
+ });
|
|
|
+ }.width('100%').justifyContent(FlexAlign.SpaceBetween) // 设置行的宽度和内容对齐方式
|
|
|
+ .padding({ left: 40, right: 40 }); // 设置左右内边距
|
|
|
+ });
|
|
|
+ }.layoutWeight(1); // 设置滚动区域占据剩余空间
|
|
|
+ }.layoutWeight(1) // 设置滚动区域占据剩余空间
|
|
|
+ .margin({ top: 20, bottom: 20 }) // 设置上下外边距
|
|
|
+ .align(Alignment.Top); // 设置对齐方式为顶部对齐
|
|
|
+
|
|
|
+ Row(){
|
|
|
+ ForEach([2,3,4,5,6],(item:number,index)=>{
|
|
|
+ Text((item).toString()).width(20).fontColor(Color.Red).onClick(()=>{
|
|
|
+ //如果当前内容
|
|
|
+ // if(this.cells.length>(item+1)){
|
|
|
+ //
|
|
|
+ //
|
|
|
+ // }
|
|
|
+ this.cells=[]
|
|
|
+ for(let i=0;i<item;i++){
|
|
|
+ this.cells.push(new Cell(i+1,1, "转盘"+(i+1), this.colorPalette[i]));
|
|
|
+ }
|
|
|
+ this.calculateAngles(); // 重新计算角度
|
|
|
+
|
|
|
+
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ Text('旋转秒数').fontColor(Color.Black)
|
|
|
+ CounterComponent({
|
|
|
+ options: {
|
|
|
+ type: CounterType.COMPACT, // 设置计数器类型为紧凑型
|
|
|
+ numberOptions: {
|
|
|
+ value: this.spinDuration/1000, // 设置计数器初始值 5
|
|
|
+ min: 1, // 设置最小值
|
|
|
+ max: 100, // 设置最大值
|
|
|
+ step: 1, // 设置步长
|
|
|
+ onChange: (value: number) => { // 计数器值变化时的回调
|
|
|
+ this.spinDuration = value*1000;
|
|
|
+ // this.calculateAngles(); // 重新计算角度
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }).backgroundColor(Color.White)
|
|
|
+
|
|
|
+
|
|
|
+ Row(){
|
|
|
+ Column(){
|
|
|
+ //是否允许结果重复
|
|
|
+ Button('是否允许结果重复').onClick(()=>{
|
|
|
+ this.isRepeat=!this.isRepeat
|
|
|
+ })
|
|
|
+ Text(this.isRepeat+"")
|
|
|
+ }
|
|
|
+
|
|
|
+ Column(){
|
|
|
+ Button('xxx').onClick(()=>{
|
|
|
+ //
|
|
|
+ // router.pushUrl({
|
|
|
+ // url:"/pages/Test2ge".slice(1)
|
|
|
+ // })
|
|
|
+ })
|
|
|
+
|
|
|
+ Button('xxxxx').onClick(()=>{
|
|
|
+ // router.pushUrl({
|
|
|
+ // url:"/pages/Index".slice(1)
|
|
|
+ // })
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ // 创建添加新内容按钮
|
|
|
+ Button('添加新内容').onClick(() => {
|
|
|
+ // 向单元格数组中添加新单元格
|
|
|
+ // this.cells.push(new Cell(1, "新内容", this.colorPalette[this.colorIndex++ % this.colorPalette.length]));
|
|
|
+ this.calculateAngles(); // 重新计算角度
|
|
|
+ }).margin({ top: 20, bottom: 20 }); // 设置按钮的上下外边距
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ }.padding({ bottom: this.safeBottom })
|
|
|
+ .justifyContent(FlexAlign.Center)
|
|
|
+ }
|
|
|
+}
|