UIView Hide/Show animate

本文介绍如何在iOS应用中实现UIView的淡入淡出动画效果,包括使用UIView动画方法、Core Animation以及创建专门的动画类别来平滑地显示和隐藏视图。

iOS UIView 隐藏和显示的动画 - 淡入 淡出 的动画效果

My simple goal is to fade animate hiding and showing functions.

Button.hidden = YES;
Simple enough. However, is it possible to have it fade out rather than just disappearing? It looks rather unprofessional that way.

ios uiviewanimation
shareimprove this question
edited Feb 12 at 17:36
asked Feb 2 '12 at 16:21

JTApps
2,22832242
add a comment
5 Answers
active oldest votes
up vote
159
down vote
accepted
In iOS 4 and later, there's a way to do this just using the UIView transition method without needing to import QuartzCore. You can just say:

[UIView transitionWithView:button
                  duration:0.4
                   options:UIViewAnimationOptionTransitionCrossDissolve
                animations:^{
                     button.hidden = YES;
                }
                completion:NULL];
Previous Solution

Michail's solution will work, but it's not actually the best approach.

The problem with alpha fading is that sometimes the different overlapping view layers look weird as they fade out. There are some other alternatives using Core Animation. First include the QuartzCore framework in your app and add #import <QuartzCore/QuartzCore.h> to your header. Now you can do one of the following:

1) set button.layer.shouldRasterize = YES; and then use the alpha animation code that Michail provided in his answer. This will prevent the layers from blending weirdly, but has a slight performance penalty, and can make the button look blurry if it's not aligned exactly on a pixel boundary.

Alternatively:

2) Use the following code to animate the fade instead:

CATransition *animation = [CATransition animation];
animation.type = kCATransitionFade;
animation.duration = 0.4;
[button.layer addAnimation:animation forKey:nil];

button.hidden = YES;
The nice thing about this approach is you can crossfade any property of the button even if they aren't animatable (e.g. the text or image of the button), just set up the transition and then set your properties immediately afterwards.

shareimprove this answer
edited May 25 at 15:43

robmathers
333315
answered Feb 2 '12 at 16:49

Nick Lockwood
33.3k79290
add a comment
up vote
83
down vote
To fade out:

[UIView animateWithDuration:0.3 animations:^{
    button.alpha = 0;
} completion: ^(BOOL finished) {//creates a variable (BOOL) called "finished" that is set to *YES* when animation IS completed.
    button.hidden = finished;//if animation is finished ("finished" == *YES*), then hidden = "finished" ... (aka hidden = *YES*)
}];

// swift:
UIView.animateWithDuration(0.3, animations: {
    button.alpha = 0
}) { (finished) in
    button.hidden = finished
}
To fade in:

button.alpha = 0;
button.hidden = NO;
[UIView animateWithDuration:0.3 animations:^{
    button.alpha = 1;
}];

// swift:
button.alpha = 0
button.hidden = false
UIView.animateWithDuration(0.3) {
    button.alpha = 1
}
shareimprove this answer
edited Sep 1 at 9:45
answered Feb 2 '12 at 16:28

Mikhail Grebionkin
1,637713
  	 	
using the fade in/out in conjunction with the hidden state solved my problem – ACLima Jun 1 at 15:58
add a comment
up vote
27
down vote
The best way:

Swift:

func setView(view: UIView, hidden: Bool) {
    UIView.transitionWithView(view, duration: 0.5, options: .TransitionCrossDissolve, animations: {() -> Void in
        view.hidden = hidden
        }, completion: { _ in })
}
Objective C:

- (void)setView:(UIView*)view hidden:(BOOL)hidden {
    [UIView transitionWithView:view duration:0.5 options:UIViewAnimationOptionTransitionCrossDissolve animations:^(void){
        [view setHidden:hidden];
    } completion:nil];
}
shareimprove this answer
edited Jun 13 at 7:31
answered Mar 16 '15 at 15:37

evya
1,0711315
3	 	
Actually this is the simple and best answer – Irshad Mohamed Aug 12 '15 at 13:21
2	 	
This one is too good. – Shahzaib Maqbool Apr 11 at 8:21
1	 	
This helped me a lot. Thanks! – Berk Kaya Aug 2 at 19:18
add a comment
up vote
5
down vote
I created category for UIView for this purpose and implemented a special little bit different concept: visibility. The main difference of my solution is that you can call [view setVisible:NO animated:YES] and right after that synchronously check [view visible] and get correct result. This is pretty simple but extremely useful.

Besides, it is allowed to avoid using "negative boolean logic" (see Code Complete, page 269, Use positive boolean variable names for more information).

Swift

UIView+Visibility.swift

import UIKit


private let UIViewVisibilityShowAnimationKey = "UIViewVisibilityShowAnimationKey"
private let UIViewVisibilityHideAnimationKey = "UIViewVisibilityHideAnimationKey"


private class UIViewAnimationDelegate: NSObject {
    weak var view: UIView?

    dynamic override func animationDidStop(animation: CAAnimation, finished: Bool) {
        guard let view = self.view where finished else {
            return
        }

        view.hidden = !view.visible
        view.removeVisibilityAnimations()
    }
}


extension UIView {

    private func removeVisibilityAnimations() {
        self.layer.removeAnimationForKey(UIViewVisibilityShowAnimationKey)
        self.layer.removeAnimationForKey(UIViewVisibilityHideAnimationKey)
    }

    var visible: Bool {
        get {
            return !self.hidden && self.layer.animationForKey(UIViewVisibilityHideAnimationKey) == nil
        }

        set {
            let visible = newValue

            guard self.visible != visible else {
                return
            }

            let animated = UIView.areAnimationsEnabled()

            self.removeVisibilityAnimations()

            guard animated else {
                self.hidden = !visible
                return
            }

            self.hidden = false

            let delegate = UIViewAnimationDelegate()
            delegate.view = self

            let animation = CABasicAnimation(keyPath: "opacity")
            animation.fromValue = visible ? 0.0 : 1.0
            animation.toValue = visible ? 1.0 : 0.0
            animation.fillMode = kCAFillModeForwards
            animation.removedOnCompletion = false
            animation.delegate = delegate

            self.layer.addAnimation(animation, forKey: visible ? UIViewVisibilityShowAnimationKey : UIViewVisibilityHideAnimationKey)
        }
    }

    func setVisible(visible: Bool, animated: Bool) {
        let wereAnimationsEnabled = UIView.areAnimationsEnabled()

        if wereAnimationsEnabled != animated {
            UIView.setAnimationsEnabled(animated)
            defer { UIView.setAnimationsEnabled(!animated) }
        }

        self.visible = visible
    }

}
Objective-C

UIView+Visibility.h

#import <UIKit/UIKit.h>

@interface UIView (Visibility)

- (BOOL)visible;
- (void)setVisible:(BOOL)visible;
- (void)setVisible:(BOOL)visible animated:(BOOL)animated;

@end
UIView+Visibility.m

#import "UIView+Visibility.h"

NSString *const UIViewVisibilityAnimationKeyShow = @"UIViewVisibilityAnimationKeyShow";
NSString *const UIViewVisibilityAnimationKeyHide = @"UIViewVisibilityAnimationKeyHide";

@implementation UIView (Visibility)

- (BOOL)visible
{
    if (self.hidden || [self.layer animationForKey:UIViewVisibilityAnimationKeyHide]) {
        return NO;
    }

    return YES;
}

- (void)setVisible:(BOOL)visible
{
    [self setVisible:visible animated:NO];
}

- (void)setVisible:(BOOL)visible animated:(BOOL)animated
{
    if (self.visible == visible) {
        return;
    }

    [self.layer removeAnimationForKey:UIViewVisibilityAnimationKeyShow];
    [self.layer removeAnimationForKey:UIViewVisibilityAnimationKeyHide];

    if (!animated) {
        self.alpha = 1.f;
        self.hidden = !visible;
        return;
    }

    self.hidden = NO;

    CGFloat fromAlpha = visible ? 0.f : 1.f;
    CGFloat toAlpha = visible ? 1.f : 0.f;
    NSString *animationKey = visible ? UIViewVisibilityAnimationKeyShow : UIViewVisibilityAnimationKeyHide;

    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
    animation.duration = 0.25;
    animation.fromValue = @(fromAlpha);
    animation.toValue = @(toAlpha);
    animation.delegate = self;
    animation.removedOnCompletion = NO;
    animation.fillMode = kCAFillModeForwards;
    [self.layer addAnimation:animation forKey:animationKey];
}

#pragma mark - CAAnimationDelegate

- (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)finished
{
    if ([[self.layer animationForKey:UIViewVisibilityAnimationKeyHide] isEqual:animation]) {
        self.hidden = YES;
    }
}

@end
shareimprove this answer
edited Apr 27 at 0:09
answered Dec 25 '14 at 12:14

Valentin Shergin
2,66212235
1	 	
This is very nice. Thank you for posting this. – Alex Zavatone Jun 9 '15 at 17:31
  	 	
@valentin shergin Swift version is coming? – Juan Pablo Boero Alvarez Mar 15 at 17:35 
  	 	
Sure! I have added Swift version. – Valentin Shergin Apr 27 at 0:09
add a comment
up vote
0
down vote
You can do it VERY easily using Animatics library:

//To hide button:
AlphaAnimator(0) ~> button

//to show button
AlphaAnimator(1) ~> button
shareimprove this answer


同上你看看我这个类还有什么没有删 或者还有什么没有加的import uiBase from "./uiBase.js"; import { Container, Graphics, Text, Assets, Sprite, Texture } from "pixi.js"; import gameData from "../Frame/gameDataMgr.js"; import networkMgr from "../Frame/networkMgr.js"; import { UIManager } from "../Frame/uiManager.js"; import { BlackMaskBg } from "../Frame/CommonUI/blackMaskBg"; import { LocalSprite } from "../Frame/CommonUI/LocalSprite"; import { UIBankData } from "../UIView/uiBankData.js"; class uiShop extends uiBase { mainContainer; // 主界面容器 blockBg; // 背景遮罩 shopBg3Container; // 弹窗容器 shopBgButton; // 按钮 buttonText; // 按钮文字 closeButton; // 叉叉按钮 introduceText; // 介绍背景 isInist = false; isPivotInitialized = false; CONTAINER_WIDTH = 650; CONTAINER_HEIGHT = 400; shopGoodsList = []; _rpLabel = gameData.currencySign; // 使用动态货币符号 // 记录当前选中的索引和金额值 selectedIndex = -1; // 当前选中的金额框索引 selectedAmountValue = 0; // 当前选中的金额数值 selectedStarCount = 0; // 当前赠送的星数 id = 0; // 当前选中的id inputDisplayText; // 显示选中金额的文本 rechargeYes; // 可点击亮色图 rechargeNo; // 不可点击灰色图 depositHistory; // 历史记录按钮 depositHistoryText; // 历史记录文本 // =====银行选择弹窗容器 ===== bankPopupContainer; // 充值支付银行弹窗容器 bankList = []; // 银行列表数据 bankSprites = []; // 银行图标精灵数组 bankShineSprites = []; // 银行图标发光边框数组 selectedBankIndex = -1; // 当前选中的银行索引 selectedBankData = null; // 当前选中的银行数据 bankConfirmYes; // 银行确认按钮亮色 bankConfirmNo; // 银行确认按钮灰色 // =====支付成功展示 ===== paymentSuccessContainer; // 支付成功展示容器 paymentAmountText; // 支付金额文本 paymentConfirmButton; // 支付成功确认按钮 scrollContainer; //创建滚动容器 // =====历史记录弹窗容器 ===== historyListContainer; recordList = []; historyTextObjects = []; // 用于存储每条记录的所有文本对象(因为要每条记录都参与本地化) bank=null; async init() { super.init(); // 创建主界面容器 this.mainContainer = new Container(); this.mainContainer.position.set(330, 210); this.container.addChild(this.mainContainer); // 预加载资源 await Assets.load([ "assets/UIShop/+.png", "assets/UIShop/复制.png", "assets/UIShop/商店底1_1.png", "assets/UIShop/商店底2.png", "assets/UIShop/商店底3.png", "assets/UIShop/赠送底.png", "assets/UIShop/赠送金额底.png", "assets/UIShop/UI1_02.png", "assets/UIShop/UI1_03.png", "assets/UIShop/UI1_05.png", "assets/UIShop/UI1_07.png", "assets/UIShop/UI1_09_2.png", "assets/UIShop/UI1_09.png", "assets/UIShop/UI1_11.png", "assets/UIShop/UI1_14.png", "assets/UIShop/UI1_17.png", "assets/UIShop/UI1_22.png", "assets/UIShop/商店底4.png", "assets/UIShop/UI8_6.png", "assets/UIShop/WithdrawalBankIcon_DANA.png", "assets/UIShop/WithdrawalBankIcon_OVO.png", "assets/UIShop/WithdrawalBankIcon_QRIS.png", "assets/UIShop/WithdrawalBankIcon_BNI.png", "assets/UIShop/WithdrawalBankIcon_BRI.png", "assets/UIShop/WithdrawalBankIcon_ALLIANCE.png", "assets/UIShop/WithdrawalBankIcon_BCA.png", "assets/UIShop/WithdrawalBankIcon_BIMB.png", "assets/UIShop/商店底5.png", "assets/UIShop/复制.png", "assets/UIShop/商店底1_12.png", ]); // 获取商店数据 await this.SendShopData(); // === 主界面内容 === // 创建主界面后面黑幕 const app = this.app; this.overallWidth = app.screen.width; this.overallHeight = app.screen.height; const opacity = 0.6; //黑幕 const blackMask = new Graphics(); blackMask.beginFill(0x000000, opacity); blackMask.drawRect(-this.overallWidth * 0.51, -this.overallHeight * 0.53, this.overallWidth*1.13, this.overallHeight); blackMask.endFill(); this.mainContainer.addChild(blackMask); //黑幕 //let blackMask = new BlackMaskBg({ parent: this.mainContainer }); const shopBg2 = new Sprite(Texture.from("assets/UIShop/商店底1_12.png")); shopBg2.width = this.overallWidth; shopBg2.height = this.overallHeight; const offsetX = -this.overallWidth * 0.5; // 向左偏移整体宽度的 50% const offsetY = -this.overallHeight * 0.53; // 向上偏移高度的 20% shopBg2.position.set(offsetX, offsetY); this.closeButton = new Sprite(Texture.from("assets/UIShop/UI1_03.png")); //主界面叉叉按钮 this.closeButton.width = 40; this.closeButton.height = 40; this.closeButton.anchor.set(1, 0); this.closeButton.position.set(this.overallWidth/2-10, -this.overallHeight/2); this.closeButton.eventMode = "static"; this.closeButton.cursor = "pointer"; this.closeButton.on("pointerdown", () => this.hide()); const textX = shopBg2.position.x + shopBg2.width * 0.5; const textY = shopBg2.position.y+10; // 主界面装饰文本 this.depositText = Object.assign( new Text("存款deposit", { fontFamily: "Arial", fontSize: 35, fill: 0xffff84, align: "center", stroke: "#FFA500", strokeThickness: 2, fontWeight: "bold", }), { anchor: { x: 0.5, y: 0 }, position: { x: textX, y: textY } }, ); this.topUpAmountText = Object.assign( new Text("haha", { fontFamily: "Arial", fontSize: 14, fill: 0xcf9f6c, align: "center", fontWeight: "bold", }), { anchor: { x: 0.5, y: 0 },position: { x: this.overallWidth * -0.15, y:this.overallHeight* -0.3 } }, ); this.inputAmountText = Object.assign( new Text("haha", { fontFamily: "Arial", fontSize: 14.5, fill: 0xd37744, align: "center", }), { anchor: { x: 0.5, y: 0 }, position: { x: this.overallWidth * -0.12, y:this.overallHeight* -0.23 } }, ); const inputBox = new Sprite(Texture.from("assets/UIShop/UI1_02.png")); // 输入框图 inputBox.width *= this.app.rat; inputBox.height *= this.app.rat; inputBox.anchor.set(0.5, 0.5); inputBox.position.set( this.overallWidth * -0.10+5, this.overallHeight* -0.21, ); // 显示选中金额的文本 this.inputDisplayText = new Text("", { fontSize: 18, fill: 0xb18b5b, fontFamily: "Arial", fontWeight: "bold", }); this.inputDisplayText.anchor.set(0.5); this.inputDisplayText.position.set( this.overallWidth * -0.15, this.overallHeight* -0.21, ); this.inputDisplayText.visible = false; // 初始不显示 const clearInput = new Sprite(Texture.from("assets/UIShop/UI1_17.png")); // 输入框里的叉叉 clearInput.width *= this.app.rat+0.2; clearInput.height *= this.app.rat+0.1; clearInput.anchor.set(0.5, 0.5); clearInput.position.set( this.overallWidth * 0.07, this.overallHeight* -0.21, ); clearInput.eventMode = "static"; clearInput.cursor = "pointer"; // 绑定叉叉点击事件:清除输入框中的金额 clearInput.on("pointerdown", () => { if (this.inputDisplayText.visible) { this.clearSelection(); // 清除状态 } }); const addPicture = new Sprite(Texture.from("assets/UIShop/+.png")); // 加号图 addPicture.width *= this.app.rat; addPicture.height *= this.app.rat; addPicture.anchor.set(0.5, 0.5); addPicture.position.set( this.overallWidth * 0.15, this.overallHeight* -0.21, ); const givePicture = new Sprite( Texture.from("assets/UIShop/赠送金额底.png"), ); // 赠送金额底 givePicture.width *= this.app.rat; givePicture.height *= this.app.rat; givePicture.anchor.set(0.5, 0.5); givePicture.position.set( this.overallWidth * 0.29, this.overallHeight* -0.21, ); const givePicture2 = new Sprite(Texture.from("assets/UIShop/赠送底.png")); // 赠送底 givePicture2.width *= this.app.rat; givePicture2.height *= this.app.rat; givePicture2.anchor.set(0.5, 0.5); givePicture2.position.set( this.overallWidth * 0.29, this.overallHeight* -0.21, ); this.freeAmountText = Object.assign( new Text("haha", { fontFamily: "Arial", fontSize: 11, fill: 0xcf9f6c, align: "center", fontWeight: "bold", }), { anchor: { x: 0.5, y: 0.5 }, position: { x: this.overallWidth * 0.29, y:this.overallHeight* -0.26 } }, ); this.rpText = Object.assign( new Text("haha", { fontFamily: "Arial", fontSize: 25, fill: 0xffffff, align: "center", fontWeight: "bold", }), { anchor: { x: 0.5, y: 0.5 }, position: { x: this.overallWidth * 0.28, y:this.overallHeight* -0.18 } }, ); this.selectAmountText = Object.assign( new Text("haha", { fontFamily: "Arial", fontSize: 15, fill: 0xcf9f6c, align: "center", fontWeight: "bold", }), { anchor: { x: 0.5, y: 0.5 }, position: { x: this.overallWidth * -0.1, y:this.overallHeight* -0.12 } }, ); //添加到舞台 画面上 this.mainContainer.addChild( shopBg2, // shopBg1, this.closeButton, inputBox, clearInput, addPicture, givePicture, givePicture2, ); this.mainContainer.addChild( this.depositText, this.topUpAmountText, this.inputAmountText, this.freeAmountText, this.rpText, this.selectAmountText, this.inputDisplayText, ); console.log("看一下有没有赋值进去~~~", this.shopGoodsList); // 创建金额框图8个、小红角星8张、发光边框8个 this.amountSprites = []; // 存储所有金额图的数组 this.starSprites = []; // 存储所有五角星的数组 this.shineSprites = []; // 存储所有发光边框的数组 this.selectedIndex = -1; // 当前选中的索引,-1表示没有选中 // === 创建滚动容器 === this.scrollContainer = new Container(); this.scrollContainer.x = 0; this.scrollContainer.y = 0; this.mainContainer.addChild(this.scrollContainer); // === 设置滚动参数 === const visibleRows = 2; // 显示2排 const colsPerRow = 4; // 每排3个 const totalRows = Math.ceil(this.shopGoodsList.length / colsPerRow); // 总排数 const scrollableHeight = (totalRows - visibleRows) * 60; // 可滚动的高度 // === 设置遮罩,限制显示区域 === const mask = new Graphics(); mask.beginFill(0x000000, opacity); mask.drawRect(-this.overallWidth * 0.51, -this.overallHeight * 0.53, this.overallWidth*1.13, this.overallHeight); mask.endFill(); this.scrollContainer.mask = mask; this.mainContainer.addChild(mask); // 调整金额框的间距参数 const startX = this.overallWidth * -0.2; // 起始X坐标 const startY = this.overallHeight* 0.01; // 起始Y坐标 const spacingX = 100; // X轴间距(左右间隔) const spacingY = 60; // Y轴间距(上下间隔) for (let i = 0; i < this.shopGoodsList.length; i++) { // 1. 创建发光边框图 const shine = new Sprite(Texture.from("assets/UIShop/UI1_11.png")); shine.width *= this.app.rat; shine.height *= this.app.rat; shine.anchor.set(0.5, 0.5); shine.visible = false; // 初始隐藏,只有选中时才显示 // 2. 创建金额框图 const amount = new Sprite(Texture.from("assets/UIShop/UI1_22.png")); amount.width *= this.app.rat; amount.height *= this.app.rat; amount.anchor.set(0.5, 0.5); amount.interactive = true; // 启用点击交互 amount.buttonMode = true; // 鼠标移到上面变成手型 // 3. 创建小红角星图 const star = new Sprite(Texture.from("assets/UIShop/UI1_14.png")); star.width *= this.app.rat; star.height *= this.app.rat; star.anchor.set(0.5, 0.5); // 4. 创建文本显示 - 金额 const amountText = new Text("", { fontSize: 15, fill: 0xff7e36, // 橘色 fontFamily: "Arial", }); amountText.anchor.set(0.5, 0.5); amountText.interactive = true; // 启用点击交互 amountText.buttonMode = true; // 鼠标移到上面变成手型 amountText.cursor = "pointer"; // 设置鼠标指针为手型 // 5. 创建文本显示 - 星星 const starText = new Text("", { fontSize: 11, fill: 0xffffff, // 白色 fontWeight: "normal", fontFamily: "Arial, sans-serif", }); starText.anchor.set(0.5, 0.5); starText.interactive = true; // 启用点击交互 starText.buttonMode = true; // 鼠标移到上面变成手型 starText.cursor = "pointer"; // 设置鼠标指针为手型 // 计算位置(每排3个,多排) const row = Math.floor(i / colsPerRow); const col = i % colsPerRow; const xPos = startX + col * spacingX; const yPos = startY + row * spacingY; // 设置所有元素的位置 shine.position.set(xPos, yPos); // 发光边框在底层 amount.position.set(xPos, yPos); // 金额框在中间 star.position.set(xPos + 18, yPos - 22); // 五角星在金额框右上方 amountText.position.set(xPos, yPos + 2); // 金额文本在金额框中心偏下 starText.position.set(xPos + 18, yPos - 25); // 星星数量文本在五角星中心 // shopGoodsList获取数据 let item, extraItem, count, starCount, id; if (this.shopGoodsList && this.shopGoodsList[i]) { item = this.shopGoodsList[i].items[0]; extraItem = this.shopGoodsList[i].extraItems[0]; count = item ? item.count : 0; starCount = extraItem ? extraItem.count : 0; id = this.shopGoodsList[i].id; } else { count = 0; starCount = 0; id = 0; } // 设置金额文本 const label = this._rpLabel; amountText.text = count > 0 ? `${label} ${count}` : "0"; // 只有当starCount大于0时才显示星星图片和文本 if (starCount > 0) { starText.text = `+${starCount}`; star.visible = true; starText.visible = true; star.interactive = true; star.buttonMode = true; } else { starText.text = ""; star.visible = false; starText.visible = false; star.interactive = false; star.buttonMode = false; } // 创建点击处理函数 const handleItemClick = () => { if (this.bankPopupContainer && this.bankPopupContainer.visible) { // 如果支付弹窗已显示 return; } // 先隐藏所有发光边框 for (let j = 0; j < this.shineSprites.length; j++) { this.shineSprites[j].visible = false; } // 显示当前点击的发光边框 this.shineSprites[i].visible = true; this.selectedIndex = i; this.selectedAmountValue = count; this.selectedStarCount = starCount; this.id = id; this.inputDisplayText.text = `${label} ${count}`; //// 输入框显示为"货币" this.inputDisplayText.visible = true; this.inputAmountText.visible = false; // 隐藏提示文字 // rpText 显示为纯数字 this.rpText.text = `${this._rpLabel} ${this.formatNumberWithUnit(starCount)}`; console.log( "选中了第", i + 1, "个金额图,金额:", count, "赠送星:", starCount, "id:", id, ); // 选中后切换为亮色可点击按钮 if (this.rechargeYes && this.rechargeNo) { this.rechargeYes.visible = true; this.rechargeNo.visible = false; this.rechargeYes.eventMode = "static"; this.rechargeYes.cursor = "pointer"; } }; // 给金额图添加点击事件 amount.on("pointerdown", handleItemClick); // 给金额文本添加点击事件 amountText.on("pointerdown", handleItemClick); // 当starCount大于0时,才给星星图片和文本添加点击事件 if (starCount > 0) { star.on("pointerdown", handleItemClick); starText.on("pointerdown", handleItemClick); } // 将创建的元素存储到数组 this.amountSprites.push(amount); this.starSprites.push(star); this.shineSprites.push(shine); // 按层级顺序添加到滚动容器(从下到上) this.scrollContainer.addChild(amount); // 最底层:金额图 this.scrollContainer.addChild(shine); // 中间层:发光边框 // 只有当starCount大于0时,才添加星星图片和文本到容器 if (starCount > 0) { this.scrollContainer.addChild(star); // 最上层:五角星 this.scrollContainer.addChild(starText); // 星星数量文本 } this.scrollContainer.addChild(amountText); // 金额文本 } // === 添加滚动功能 === if (scrollableHeight > 0) { // 只有需要滚动时才添加滚动功能 let isDragging = false; let lastY = 0; let currentScrollY = 0; // 鼠标/触摸按下事件 this.scrollContainer.interactive = true; this.scrollContainer.on("mousedown", (event) => { isDragging = true; lastY = event.data.global.y; }); this.scrollContainer.on("touchstart", (event) => { isDragging = true; lastY = event.data.global.y; }); // 鼠标/触摸移动事件 this.scrollContainer.on("mousemove", (event) => { if (isDragging) { const deltaY = event.data.global.y - lastY; lastY = event.data.global.y; // 更新滚动位置,限制在可滚动范围内 currentScrollY += deltaY; currentScrollY = Math.max( -scrollableHeight, Math.min(0, currentScrollY), ); this.scrollContainer.y = currentScrollY; } }); this.scrollContainer.on("touchmove", (event) => { if (isDragging) { const deltaY = event.data.global.y - lastY; lastY = event.data.global.y; // 更新滚动位置,限制在可滚动范围内 currentScrollY += deltaY; currentScrollY = Math.max( -scrollableHeight, Math.min(0, currentScrollY), ); this.scrollContainer.y = currentScrollY; } }); // 鼠标/触摸释放事件 this.scrollContainer.on("mouseup", () => { isDragging = false; }); this.scrollContainer.on("touchend", () => { isDragging = false; }); this.scrollContainer.on("mouseupoutside", () => { isDragging = false; }); this.scrollContainer.on("touchendoutside", () => { isDragging = false; }); // 鼠标滚轮事件 this.scrollContainer.on("wheel", (event) => { const scrollAmount = event.deltaY > 0 ? 30 : -30; // 滚轮滚动量 // 更新滚动位置,限制在可滚动范围内 currentScrollY += scrollAmount; currentScrollY = Math.max( -scrollableHeight, Math.min(0, currentScrollY), ); this.scrollContainer.y = currentScrollY; }); } // === 充值按钮:亮色(可点)与灰色(不可点)切换 === const rechargeYes = new Sprite(Texture.from("assets/UIShop/UI1_09.png")); // 可点击亮色图 rechargeYes.width *= this.app.rat; rechargeYes.height *= this.app.rat; rechargeYes.anchor.set(0.5, 0.5); rechargeYes.position.set(-20, 140); rechargeYes.visible = false; // 初始隐藏 rechargeYes.eventMode = "static"; // 启用交互 rechargeYes.cursor = "pointer"; const rechargeNo = new Sprite(Texture.from("assets/UIShop/UI1_09_2.png")); // 不可点击灰色图 rechargeNo.width *= this.app.rat; rechargeNo.height *= this.app.rat; rechargeNo.anchor.set(0.5, 0.5); rechargeNo.position.set(-20, 140); rechargeNo.visible = true; // 初始显示 rechargeNo.eventMode = "none"; rechargeNo.cursor = "default"; // 创建按钮文字 - 保持你的本地化逻辑 this.depositText2 = Object.assign( new Text("嘟嘟嘟", { fontFamily: "Arial", fontSize: 25, fill: 0xffffff, align: "center", stroke: "#FFA500", }), { anchor: { x: 0.5, y: 0.5 } } ); // 灰色按钮的文字 const depositTextNo = Object.assign( new Text("嘟嘟嘟", { fontFamily: "Arial", fontSize: 25, fill: 0xcccccc, // 灰色文字 align: "center", }), { anchor: { x: 0.5, y: 0.5 } } ); this.depositText2.position.set(0, -5); // 相对于亮色按钮的位置 depositTextNo.position.set(0, -5); // 相对于灰色按钮的位置 rechargeYes.addChild(this.depositText2); rechargeNo.addChild(depositTextNo); // 添加到主容器 this.mainContainer.addChild(rechargeYes, rechargeNo); this.rechargeYes = rechargeYes; this.rechargeNo = rechargeNo; // 保存灰色按钮文字引用 this.depositTextNo = depositTextNo; // 绑定点击事件 rechargeYes.on("pointerdown", async () => { // 先检查是否选择了金额 if (this.selectedIndex === -1) return; // 设置回调:当用户在银行弹窗点击【确认】时执行的操作 UIBankData.onPaymentRequest = async (selectedBank) => { // 执行支付请求 await this.sendPaymentRequest(selectedBank); // 关闭银行弹窗 UIBankData.hide(); }; // 显示银行弹窗(传入当前商品 ID) await UIBankData.showForGoods(this.id); }); // =======支付成功展示容器开始========= this.paymentSuccessContainer = new Container(); this.paymentSuccessContainer.visible = false; // 初始隐藏 this.paymentSuccessContainer.zIndex = 200; // 最高层级 this.paymentSuccessContainer.eventMode = "static"; // 启用交互 // 创建全屏透明背景 const successOverlay = new Graphics(); successOverlay.beginFill(0x000000, 0.01); // 透明 successOverlay.drawRect(-375, -667, 750, 1334); successOverlay.endFill(); this.paymentSuccessContainer.addChild(successOverlay); // 创建支付金额文本 this.paymentAmountText = new Text("", { fontFamily: "Arial", fontSize: 60, fill: 0xffff00, // 黄色 align: "center", fontWeight: "bold", stroke: "#000000", strokeThickness: 4, }); this.paymentAmountText.anchor.set(0.5); this.paymentAmountText.position.set(0, 0); this.paymentSuccessContainer.addChild(this.paymentAmountText); // 创建确认按钮 this.createPaymentConfirmButton(); // 点击任意位置隐藏支付成功展示 this.paymentSuccessContainer.on("pointerdown", (event) => { // 检查点击的是否是确认按钮,如果不是则隐藏 if ( !event.target || !event.target.parent || event.target.parent !== this.paymentConfirmButton ) { this.hidePaymentSuccess(); } }); // 将支付成功容器添加到根容器 this.container.addChild(this.paymentSuccessContainer); // =======支付成功展示容器结束========= this.depositHistory = new Sprite(Texture.from("assets/UIShop/UI1_05.png")); //历史记录图按钮 this.depositHistory.width *= this.app.rat; this.depositHistory.height *= this.app.rat; this.depositHistory.anchor.set(0.5, 0.5); this.depositHistory.position.set(this.overallWidth/2-110, this.overallHeight/2-50); this.depositHistory.interactive = true; this.depositHistory.buttonMode = true; this.mainContainer.addChild(this.depositHistory); const threeStripes = new Sprite(Texture.from("assets/UIShop/UI1_07.png")); //三条杠图(历史) threeStripes.width *= this.app.rat; threeStripes.height *= this.app.rat; threeStripes.anchor.set(0.5, 0.5); threeStripes.position.set(this.overallWidth/2-160, this.overallHeight/2-50); threeStripes.interactive = true; // 添加交互 threeStripes.buttonMode = true; // 添加按钮模式 this.depositHistoryText = Object.assign( //提示历史文字(主界面点击的历史) new Text("haha", { fontFamily: "Arial", fontSize: 12, fill: 0xd87910, align: "center", }), { anchor: { x: 0.5, y: 0.5 }, position: { x: this.overallWidth/2-105, y: this.overallHeight/2-50 } }, ); this.depositHistoryText.interactive = true; // 添加交互 this.depositHistoryText.buttonMode = true; // 添加按钮模式 this.mainContainer.addChild(threeStripes, this.depositHistoryText); // 创建统一的点击处理函数 const handleHistoryClick = async () => { // 如果支付弹窗已显示,忽略点击 if (this.bankPopupContainer && this.bankPopupContainer.visible) { return; } console.log("depositHistory 被点击了"); await this.SendHistoryData(); }; // 为所有三个元素添加点击事件 this.depositHistory.on("pointerdown", handleHistoryClick); threeStripes.on("pointerdown", handleHistoryClick); this.depositHistoryText.on("pointerdown", handleHistoryClick); // === 历史记录弹窗开始=== this.historyListContainer = new Container(); this.historyListContainer.visible = false; // 默认隐藏 this.historyListContainer.zIndex = 100;//内容透明度 this.historyListContainer.position.set( this.overallWidth * -0.35, // 距离左侧 this.overallHeight * -0.3 // 距离顶部 ); // 背景图 const recordBg = new Sprite(Texture.from("assets/UIShop/商店底5.png")); recordBg.anchor.set(0.5, 0.5); recordBg.width = this.overallWidth * 1.2; recordBg.height = this.overallHeight * 1; recordBg.position.set( this.overallWidth * 0.35, this.overallHeight* 0.3, ); this.historyText = Object.assign( new Text("haha", { fontFamily: "Arial", fontSize: 20, fill: 0xfff1a5, align: "center", }), { anchor: { x: 0.5, y: 0.5 }, position: { x: this.overallWidth* 0.35, y: this.overallHeight* -0.14} }, ); this.historyListContainer.addChild(recordBg, this.historyText); // 关闭按钮 const closeHistory = new Sprite(Texture.from("assets/UIShop/UI1_03.png")); closeHistory.width *= this.app.rat; closeHistory.height *= this.app.rat; closeHistory.position.set( this.overallWidth * 0.7, this.overallHeight* -0.1, ); closeHistory.eventMode = "static"; closeHistory.cursor = "pointer"; closeHistory.on("pointerdown", () => { this.historyListContainer.visible = false; if (this.blockBg) this.blockBg.visible = false; this.enableMainContainerInteractivity(true); // 恢复主界面操作 if (this.selectedAmountValue > 0) { this.inputAmountText.visible = false; // 隐藏提示文字 } }); this.historyListContainer.addChild(closeHistory); this.container.addChild(this.historyListContainer); // === 历史记录弹窗结束 === // === 弹窗与阴影遮罩 === //黑幕 let blockBg = new BlackMaskBg({ parent: this.container }); this.blockBg=blockBg; const shopBg3 = new Sprite(Texture.from("assets/UIShop/商店底3.png")); shopBg3.width = 500; shopBg3.height = 300; shopBg3.position.set(0, 0); this.shopBg3Container = new Container(); this.shopBg3Container.position.set(-240, -140); this.shopBg3Container.addChild(shopBg3); this.container.addChild(this.shopBg3Container); this.introduceText = new Text("介绍背景", { fontFamily: "Arial", fontSize: 13, fill: 0xffffff, align: "center", stroke: " #000000", strokeThickness: 0, lineHeight: 25, }); this.introduceText.anchor.set(0.5); this.introduceText.position.set( shopBg3.width / 2 + 60, shopBg3.height / 2 - 5, ); this.shopBg3Container.addChild(this.introduceText); this.shopBgButton = new Sprite(Texture.from("assets/UIShop/UI1_09.png")); this.shopBgButton.width = 210; this.shopBgButton.height = 60; this.shopBgButton.position.set(-80, 100); this.shopBgButton.eventMode = "static"; this.shopBgButton.cursor = "pointer"; this.buttonText = new Text("哈咯", { fontSize: 28, fill: 0xffffff, align: "center", stroke: "#000000", strokeThickness: 2, }); this.buttonText.anchor.set(0.5); this.buttonText.position.set( this.shopBgButton.width / 2, this.shopBgButton.height / 2, ); this.shopBgButton.addChild(this.buttonText); this.shopBgButton.on("pointerdown", () => { // 点击按钮后隐藏弹窗 if (this.shopBg3Container) this.shopBg3Container.visible = false; if (this.shopBgButton) this.shopBgButton.visible = false; if (blockBg) blockBg.visible = false; if (this.closeButton) { this.closeButton.eventMode = "static"; this.closeButton.cursor = "pointer"; } this.enableMainContainerInteractivity(true); }); this.container.addChild(this.shopBgButton); // 只设置一次 pivot:围绕内容中心缩放 if (!this.isPivotInitialized) { this.mainContainer.pivot.set( this.CONTAINER_WIDTH / 2, this.CONTAINER_HEIGHT / 2, ); this.isPivotInitialized = true; } // 初始化状态 this.resetState(); this.localize(); this.isInist = true; } // 创建支付成功确认按钮 createPaymentConfirmButton() { // 创建确认按钮 this.paymentConfirmButton = new Sprite( Texture.from("assets/UIShop/UI1_09.png"), ); this.paymentConfirmButton.width = 200; this.paymentConfirmButton.height = 80; this.paymentConfirmButton.anchor.set(0.5, 0.5); this.paymentConfirmButton.position.set(5, 150); this.paymentConfirmButton.eventMode = "static"; this.paymentConfirmButton.cursor = "pointer"; // 创建按钮文字 this.confirmText = new Text("这是Confirm", { fontFamily: "Arial", fontSize: 30, fill: 0xffffff, align: "center", stroke: "#FFA500", }); this.confirmText.anchor.set(0.5, 0.5); this.confirmText.position.set(0, 0); this.paymentConfirmButton.addChild(this.confirmText); // 绑定点击事件 this.paymentConfirmButton.on("pointerdown", () => { this.hidePaymentSuccess(); }); // 添加到支付成功容器 this.paymentSuccessContainer.addChild(this.paymentConfirmButton); } // 显示支付成功动画 showPaymentSuccess(amount) { UIBankData.hide(); // 恢复主界面交互 this.enableMainContainerInteractivity(true); // 设置支付金额文本 显示数字 this.paymentAmountText.text = amount.toString(); // 显示支付成功容器 this.paymentSuccessContainer.visible = true; // 动画效果:透明到不透明,再放大 this.paymentAmountText.alpha = 0; this.paymentAmountText.scale.set(0.5); // 动画序列 const animate = () => { // 渐显 if (this.paymentAmountText.alpha < 1) { this.paymentAmountText.alpha += 0.05; requestAnimationFrame(animate); return; } // 放大 if (this.paymentAmountText.scale.x < 1.2) { this.paymentAmountText.scale.x += 0.02; this.paymentAmountText.scale.y += 0.02; requestAnimationFrame(animate); return; } // 缩小回正常 if (this.paymentAmountText.scale.x > 1) { this.paymentAmountText.scale.x -= 0.01; this.paymentAmountText.scale.y -= 0.01; requestAnimationFrame(animate); } }; // 开始动画 animate(); } // 隐藏支付成功展示 hidePaymentSuccess() { this.paymentSuccessContainer.visible = false; } // 启用或禁用主界面的交互性 enableMainContainerInteractivity(enable) { // 设置主容器内所有可交互元素的交互性 this.closeButton.eventMode = enable ? "static" : "none"; this.closeButton.cursor = enable ? "pointer" : "default"; // 设置金额框的交互性 for (const amount of this.amountSprites) { amount.eventMode = enable ? "static" : "none"; amount.cursor = enable ? "pointer" : "default"; } // 设置充值按钮的交互性 if (this.rechargeYes) { this.rechargeYes.eventMode = enable && this.selectedIndex !== -1 ? "static" : "none"; this.rechargeYes.cursor = enable && this.selectedIndex !== -1 ? "pointer" : "default"; } // 设置历史记录按钮的交互性 if (this.depositHistory) { this.depositHistory.eventMode = enable ? "static" : "none"; this.depositHistory.cursor = enable ? "pointer" : "default"; } // 设置清除输入按钮的交互性 const clearInput = this.mainContainer.children.find( (child) => child.texture && child.texture.textureCacheIds && child.texture.textureCacheIds.includes("assets/UIShop/UI1_17.png"), ); if (clearInput) { clearInput.eventMode = enable ? "static" : "none"; clearInput.cursor = enable ? "pointer" : "default"; } } // 清除选中状态 clearSelection() { this.inputDisplayText.visible = false; this.inputAmountText.visible = true; // 恢复提示文字 this.selectedIndex = -1; this.selectedAmountValue = 0; this.selectedStarCount = 0; this.rpText.text = `${this._rpLabel} 0`; // 恢复 rpText 为默认状态 for (const shine of this.shineSprites) { // 隐藏所有发光边框 shine.visible = false; } // 清除选择时切回灰色按钮 if (this.rechargeYes && this.rechargeNo) { this.rechargeYes.visible = false; this.rechargeNo.visible = true; this.rechargeYes.eventMode = "none"; this.rechargeYes.cursor = "default"; } } async show() { console.log(this.constructor.name + " 1"); if (!this.isInist) { await this.init(); } else { this.resetState(); } console.log(this.constructor.name + " 2"); this.container.visible = true; UIManager.hideLoading(); // 开启动画 //this.animateOpen(); } // 动画从中间向两边展开 animateOpen() { this.mainContainer.scale.set(0, 1); const duration = 500; const startTime = performance.now(); const tick = (currentTime) => { const elapsed = currentTime - startTime; const progress = Math.min(elapsed / duration, 1); const easeProgress = 1 - Math.pow(1 - progress, 2); // 缓动效果 this.mainContainer.scale.x = easeProgress; if (progress < 1) { requestAnimationFrame(tick); } }; requestAnimationFrame(tick); } resetState() { if (this.shopBg3Container) this.shopBg3Container.visible = true; if (this.shopBgButton) this.shopBgButton.visible = true; if (this.blockBg) this.blockBg.visible = true; if (this.mainContainer) { this.mainContainer.alpha = 1; this.mainContainer.scale.set(1); } if (this.closeButton) { this.closeButton.eventMode = "none"; this.closeButton.cursor = "default"; } // 重置选择状态 this.clearSelection(); this.enableMainContainerInteractivity(false); } hide() { this.container.visible = false; } //本地化 async localize() { this.uiname = "uiShop"; await super.localize(); // 使用 setLocalWords 方法统一设置本地化文本 super.setLocalWords(this.buttonText, "Confirmation"); super.setLocalWords(this.introduceText, "introduce"); super.setLocalWords(this.depositText, "deposit"); super.setLocalWords(this.depositText2, "deposit"); super.setLocalWords(this.depositTextNo, "deposit"); super.setLocalWords(this.topUpAmountText, "topUpAmount"); super.setLocalWords(this.inputAmountText, "inputAmount"); super.setLocalWords(this.freeAmountText, "freeAmount"); super.setLocalWords(this.selectAmountText, "selectAmount"); super.setLocalWords(this.depositHistoryText, "depositHistory"); super.setLocalWords(this.confirmText, "confirm"); super.setLocalWords(this.historyText, "depositHistory"); // 使用动态货币符号 this._rpLabel = gameData.currencySign; this.rpText.text = `${this._rpLabel} 0`; this.inputAmountText.visible = true; // 历史记录本地化 if (this.historyTextObjects && this.historyTextObjects.length > 0) { this.historyTextObjects.forEach((recordTexts) => { if (recordTexts.amountLabel && recordTexts.amountLabel.localKey) { super.setLocalWords(recordTexts.amountLabel, recordTexts.amountLabel.localKey); } if (recordTexts.orderLabel && recordTexts.orderLabel.localKey) { super.setLocalWords(recordTexts.orderLabel, recordTexts.orderLabel.localKey); } if (recordTexts.timeLabel && recordTexts.timeLabel.localKey) { super.setLocalWords(recordTexts.timeLabel, recordTexts.timeLabel.localKey); } if (recordTexts.statusLabel && recordTexts.statusLabel.localKey) { super.setLocalWords(recordTexts.statusLabel, recordTexts.statusLabel.localKey); } if (recordTexts.statusFinished && recordTexts.statusFinished.localKey) { super.setLocalWords(recordTexts.statusFinished, recordTexts.statusFinished.localKey); } if (recordTexts.statusProcessing && recordTexts.statusProcessing.localKey) { super.setLocalWords(recordTexts.statusProcessing, recordTexts.statusProcessing.localKey); } if (recordTexts.statusWaiting && recordTexts.statusWaiting.localKey) { super.setLocalWords(recordTexts.statusWaiting, recordTexts.statusWaiting.localKey); } }); } // 无数据提示 if (this.noDataText) { super.setLocalWords(this.noDataText, "oDataText"); } } formatNumberWithUnit(value) { if (value == null || isNaN(value)) return "0"; let formatted; if (value >= 1_000_000_000_000) { formatted = (value / 1_000_000_000_000).toFixed(2).replace(/\.00$/, ""); return `${formatted}T`; } else if (value >= 1_000_000_000) { formatted = (value / 1_000_000_000).toFixed(2).replace(/\.00$/, ""); return `${formatted}B`; } else if (value >= 1_000_000) { formatted = (value / 1_000_000).toFixed(2).replace(/\.00$/, ""); return `${formatted}M`; } else if (value >= 1_000) { formatted = (value / 1_000).toFixed(2).replace(/\.00$/, ""); return `${formatted}K`; } else { return String(value); } } // 接口请求:获取商店商品列表 async SendShopData() { const requestData = { token: gameData.gameToken, playerIndex: gameData.playerDto.playerIndex, }; console.log("发送请求参数:", requestData); const response = await networkMgr.postMessage("getShopGoods", requestData); if (!response) { throw new Error("接口返回空数据"); } this.shopGoodsList = response.shopGoodsList || response["shopGoodsList"] || []; console.log("获取商店数据:", this.shopGoodsList); if (this.isInist) { this.localize(); } } // 获取银行数据 async preloadBankData() { if (this.shopGoodsList.length > 0) { try { const requestData = { token: gameData.gameToken, playerIndex: gameData.playerDto.playerIndex, goodsId: this.shopGoodsList[0].id, }; await networkMgr.postMessage("getPaymentBank", requestData); console.log("预加载银行数据完成"); } catch (e) { console.warn("预加载银行数据失败", e); } } } // 发送支付请求 async SendPaymentRequest() { if (!this.selectedBankData || !this.id) { console.error("未选择银行或商品"); return; } try { const requestData = { token: gameData.gameToken, playerIndex: gameData.playerDto.playerIndex, goodsId: this.id, bankId: this.selectedBankData.bankId, bankCode: this.selectedBankData.bankCode, }; console.log("发送支付请求参数:", requestData); const response = await networkMgr.postMessage("payment", requestData); if (!response) { throw new Error("支付接口返回空数据"); } console.log("支付接口返回:", response); if (response.result === 0) { console.log("支付成功,金额:", response.amount); // 显示支付成功动画 this.showPaymentSuccess(response.amount); } else { // 支付失败 console.error("支付失败:", response.msg); } } catch (error) { console.error("支付请求失败:", error); } } // 历史记录接口 async SendHistoryData(isInit = false) { try { const requestData = { token: gameData.gameToken, playerIndex: gameData.playerDto.playerIndex, }; console.log("发送历史请求参数:", requestData); const response = await networkMgr.postMessage( "getPaymentRecord", requestData, ); if (!response) { throw new Error("接口返回空数据"); } this.recordList = response.recordList || response["recordList"] || []; // 渲染历史记录列表 this.renderHistoryList(); // 如果不是初始化调用,显示弹窗 if (!isInit) { this.historyListContainer.visible = true; this.blockBg.visible = true; for (const shine of this.bankShineSprites) { shine.visible = false; } this.enableMainContainerInteractivity(false); } this.localize(); } catch (error) { console.error("获取历史记录失败:", error); this.recordList = []; // 渲染列表 this.renderHistoryList(); if (!isInit) { this.historyListContainer.visible = true; this.blockBg.visible = true; this.enableMainContainerInteractivity(false); } } } // 历史记录列表 renderHistoryList() { // 清空之前的记录和文本对象 if (this.scrollContent) { this.scrollContent.removeChildren(); } this.historyTextObjects = []; // 配置 const listWidth = this.overallWidth * 0.7; const listHeight = this.overallHeight * 0.7; const itemHeight = this.overallHeight * 0.28; //每条记录的内容多高 const contentStartX = this.overallWidth *-0.01; const contentStartY = 0; // 重新创建滚动内容容器 this.scrollContent = new Container(); this.scrollContent.position.set(contentStartX, contentStartY); this.historyListContainer.addChild(this.scrollContent); // 如果没有数据,显示提示文字 if (!this.recordList || this.recordList.length === 0) { this.noDataText = new Text("暂无充值记录", { fontSize: 18, fill: 0x999999, }); this.noDataText.anchor.set(0.5); this.noDataText.position.set(listWidth / 2, 100); this.scrollContent.addChild(this.noDataText); return; } // 有数据时遍历生成每一条记录 this.recordList.forEach((record, index) => { const y = index * itemHeight; // 为每条记录创建一个对象来存储所有文本元素 const recordTexts = {}; // 圆角背景框 const bg = new Graphics(); bg.lineStyle(2, 0x7d503a, 0.6); // 边框颜色 bg.beginFill(0x7d503a, 0.3); // 背景色 bg.drawRoundedRect( 10, // x y + 5, // y listWidth - 15, // 宽:左右各留边距 itemHeight - 10, // 高:上下留空 18, // 圆角半径 ); bg.endFill(); this.scrollContent.addChild(bg); // 时间格式化 const date = new Date(record.createDate); const formattedTime = date.toLocaleString("en-US", { month: "numeric", day: "numeric", year: "numeric", hour: "numeric", minute: "2-digit", second: "2-digit", hour12: true, }); // 充值金额标签 recordTexts.amountLabel = new Text("Top up amount", { fontSize: 13, fill: 0xb88e7e, }); recordTexts.amountLabel.position.set(20, y + 12); recordTexts.amountLabel.localKey = "amountText"; // 添加本地化标识 // 充值金额值 recordTexts.amountValue = new Text(`${record.amount.toLocaleString()}`, { //recordTexts.amountValue = new Text(`${this._rpLabel} ${record.amount.toLocaleString()}`, { fontSize: 13, fill: 0xe1ae68, }); recordTexts.amountValue.position.set(180, y + 12); // 订单标签 recordTexts.orderLabel = new Text("Recharge Order", { fontSize: 13, fill: 0xb88e7e, }); recordTexts.orderLabel.position.set(20, y + 32); recordTexts.orderLabel.localKey = "rechargeOrderText"; // 订单号 recordTexts.orderId = new Text(record.id, { fontSize: 13, fill: 0xb77760, }); recordTexts.orderId.position.set(180, y + 32); // 时间标签 recordTexts.timeLabel = new Text("Top up time", { fontSize: 13, fill: 0xb88e7e, }); recordTexts.timeLabel.position.set(20, y + 52); recordTexts.timeLabel.localKey = "rechargeTimeText"; // 时间值 recordTexts.timeValue = new Text(formattedTime, { fontSize: 13, fill: 0xb77760, }); recordTexts.timeValue.position.set(180, y + 52); // 状态标签 recordTexts.statusLabel = new Text("Order status", { fontSize: 13, fill: 0xb88e7e, }); recordTexts.statusLabel.position.set(20, y + 72); recordTexts.statusLabel.localKey = "statusText"; // 状态文本 recordTexts.statusFinished = new Text("已成功", { fontSize: 12, fill: 0x00ff00, }); recordTexts.statusFinished.position.set(180, y + 72); recordTexts.statusFinished.visible = record.status === "1"; recordTexts.statusFinished.localKey = "status_1"; recordTexts.statusProcessing = new Text("在等待处理", { fontSize: 12, fill: 0xffff00, }); recordTexts.statusProcessing.position.set(180, y + 72); recordTexts.statusProcessing.visible = record.status === "0"; recordTexts.statusProcessing.localKey = "status_0"; recordTexts.statusWaiting = new Text("失败", { fontSize: 12, fill: 0xaa0000, }); recordTexts.statusWaiting.position.set(180, y + 72); recordTexts.statusWaiting.visible = !( record.status === "1" || record.status === "0" ); recordTexts.statusWaiting.localKey = "status_2"; // 添加到滚动容器 this.scrollContent.addChild( recordTexts.amountLabel, recordTexts.amountValue, recordTexts.orderLabel, recordTexts.orderId, recordTexts.timeLabel, recordTexts.timeValue, recordTexts.statusLabel, recordTexts.statusFinished, recordTexts.statusProcessing, recordTexts.statusWaiting, ); // 存储到数组 this.historyTextObjects.push(recordTexts); // 复制图标(点击复制订单号) const copyIcon = new Sprite(Texture.from("assets/UIShop/复制.png")); copyIcon.width = 55 * this.app.rat; copyIcon.height = 55 * this.app.rat; copyIcon.anchor.set(0.5); copyIcon.position.set(listWidth - 40, y + itemHeight / 2); // 靠右居中 copyIcon.eventMode = "static"; copyIcon.cursor = "pointer"; copyIcon.on("pointerdown", (e) => { e.stopPropagation(); navigator.clipboard .writeText(record.id) .then(() => { console.log(`已复制订单号: ${record.id}`); copyIcon.tint = 0x00ff00; setTimeout(() => { copyIcon.tint = 0xffffff; }, 300); }) .catch((err) => { alert("复制失败,请手动选择文本复制"); console.warn("Clipboard error:", err); }); }); this.scrollContent.addChild(copyIcon); }); // 限制可见范围 const clipMask = new Graphics(); clipMask.beginFill(0x000000, 0.01); clipMask.drawRect(0, 0, listWidth, listHeight); clipMask.endFill(); clipMask.position.set(0, 0); this.historyListContainer.addChild(clipMask); this.scrollContent.mask = clipMask; // 添加拖拽滚动功能 this.setupHistoryScroll(); } // 设置历史记录滚动功能 setupHistoryScroll() { const listHeight = 250; // 显示区域高度 const itemHeight = 95; // 每条记录的高度 let isDragging = false; let dragStartY = 0; let scrollStartY = 0; this.app.view.removeEventListener( "pointermove", this.handleHistoryPointerMove, ); this.app.view.removeEventListener("pointerup", this.handleHistoryPointerUp); this.app.view.removeEventListener( "pointerupoutside", this.handleHistoryPointerUp, ); this.handleHistoryPointerMove = (e) => { if (!isDragging) return; const dy = e.clientY - dragStartY; let newY = scrollStartY + dy; const maxScrollUp = 0; const totalItemsHeight = this.recordList.length * itemHeight; const maxScrollDown = listHeight - totalItemsHeight; if (newY > maxScrollUp) newY = maxScrollUp; else if (newY < maxScrollDown) newY = maxScrollDown; this.scrollContent.y = newY; }; this.handleHistoryPointerUp = () => { isDragging = false; this.scrollContent.cursor = "grab"; }; // 设置滚动容器的交互 this.scrollContent.eventMode = "static"; this.scrollContent.cursor = "grab"; this.scrollContent.on("pointerdown", (event) => { isDragging = true; dragStartY = event.global.y; scrollStartY = this.scrollContent.y; this.scrollContent.cursor = "grabbing"; event.stopPropagation(); }); // 绑定全局事件 this.app.view.addEventListener( "pointermove", this.handleHistoryPointerMove, ); this.app.view.addEventListener("pointerup", this.handleHistoryPointerUp); this.app.view.addEventListener( "pointerupoutside", this.handleHistoryPointerUp, ); } // 提供给外部 async sendPaymentRequest(bankData) { if (!bankData || !this.id) { console.error("缺少必要参数:bankData 或 goodsId"); return; } try { const requestData = { token: gameData.gameToken, playerIndex: gameData.playerDto.playerIndex, goodsId: this.id, bankId: bankData.bankId, bankCode: bankData.bankCode, }; const response = await networkMgr.postMessage("payment", requestData); if (response && response.result === 0) { console.log("支付成功,金额:", response.amount); this.showPaymentSuccess(response.amount); } else { console.error("支付失败:", response?.msg || "未知错误"); } } catch (error) { console.error("支付请求异常:", error); } } } export const UIShop = new uiShop();
最新发布
12-10
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值