reduce on-screen widget visual effect performance cost

This commit is contained in:
TrueZhuanjia
2025-08-27 22:35:47 +08:00
parent 6bae985e2c
commit 49ed0e43e9
2 changed files with 111 additions and 66 deletions
+93 -54
View File
@@ -508,9 +508,14 @@ import UIKit
setupButtonDownVisualEffectLayer();
if CommandManager.directionPads.contains(touchPadString) {setupLrudDirectionIndicatorlayers()}
if CommandManager.stickTouchPads.contains(touchPadString) {self.l3r3Indicator = createl3r3Indicator()}
if self.hasStickIndicator {
if self.crossMarkLayer.superlayer == nil {self.crossMarkLayer = createCrossMark()}
if self.stickBallLayer.superlayer == nil {self.stickBallLayer = createStickBall()}
}
}
private func createAndShowl3r3Indicator() -> CAShapeLayer{
private func createl3r3Indicator() -> CAShapeLayer{
let indicatorFrame = CAShapeLayer();
let indicatorBorder = CAShapeLayer();
@@ -525,18 +530,26 @@ import UIKit
indicatorBorder.fillColor = UIColor.clear.cgColor
let path = UIBezierPath(roundedRect: indicatorBorder.bounds, cornerRadius: indicatorBorder.cornerRadius)
indicatorBorder.path = path.cgPath
indicatorBorder.borderColor = voidlinkPurple
indicatorBorder.borderColor = UIColor.clear.cgColor
self.layer.superlayer?.addSublayer(indicatorBorder)
indicatorBorder.position = CGPointMake(CGRectGetMinX(self.frame)+touchBeganLocation.x, CGRectGetMinY(self.frame)+touchBeganLocation.y)
return indicatorBorder
}
private func showl3r3Indicator(){
CATransaction.begin()
CATransaction.setDisableActions(true)
self.l3r3Indicator.borderColor = voidlinkPurple
self.l3r3Indicator.position = CGPointMake(CGRectGetMinX(self.frame)+touchBeganLocation.x, CGRectGetMinY(self.frame)+touchBeganLocation.y)
CATransaction.commit()
if vibrationOn {
vibrationGenerator.prepare()
vibrationGenerator.impactOccurred()
// print("vibrationInstance: \(vibrationGenerator)")
}
return indicatorBorder
}
@@ -544,10 +557,13 @@ import UIKit
//Indicator overlay for on-screen game controller left or right sticks (non-vector mode)
private func handleStickBallReachingBorder(){
CATransaction.begin()
CATransaction.setDisableActions(true)
stickBallLayer.lineWidth = 0.6
// stickBallLayer.shadowOffset = CGSize(width: 0.0, height: 0.0)
stickBallLayer.shadowOffset = CGSize(width: 0.0, height: 0.0)
// stickBallLayer.shadowColor = stickBallLayer.strokeColor
CATransaction.commit()
}
private func handleStickBallLeavingBorder(){
@@ -570,13 +586,30 @@ import UIKit
stickMarkerRelativeLocation = CGPointMake(touchBeganLocation.x, touchBeganLocation.y)
}
self.crossMarkLayer = createAndShowCrossMarkOnTouchPoint(at: stickMarkerRelativeLocation)
self.stickBallLayer = createAndShowStickBall(at: stickMarkerRelativeLocation)
showStickBall(at: stickMarkerRelativeLocation)
showCrossMarkOnTouchPoint(at: stickMarkerRelativeLocation)
}
// cross mark for left & right gamePad
private func createAndShowCrossMarkOnTouchPoint(at point: CGPoint) -> CAShapeLayer {
private func createCrossMark() -> CAShapeLayer {
let crossLayer = CAShapeLayer()
crossLayer.strokeColor = crossMarkColor
crossLayer.lineWidth = 1.2
crossLayer.fillColor = crossMarkColor
self.layer.superlayer?.addSublayer(crossLayer)
crossLayer.shadowColor = UIColor.black.cgColor
crossLayer.shadowOffset = CGSize(width: 1, height: 1)
crossLayer.shadowRadius = 0;
crossLayer.shadowOpacity = 0.8
crossLayer.isHidden = true
return crossLayer
}
private func showCrossMarkOnTouchPoint(at point: CGPoint) {
let path = UIBezierPath()
let crossSize = 26.0
@@ -587,34 +620,22 @@ import UIKit
path.move(to: CGPoint(x: point.x, y: point.y - crossSize / 2))
path.addLine(to: CGPoint(x: point.x, y: point.y + crossSize / 2))
crossLayer.path = path.cgPath
crossLayer.strokeColor = crossMarkColor
crossLayer.lineWidth = 1.2
crossLayer.fillColor = crossMarkColor
CATransaction.begin()
CATransaction.setDisableActions(true)
self.layer.superlayer?.addSublayer(crossLayer)
crossLayer.position = CGPointMake(CGRectGetMinX(self.frame), CGRectGetMinY(self.frame))
// crossLayer.shadowRadius = 1
crossLayer.shadowColor = UIColor.black.cgColor
crossLayer.shadowOffset = CGSize(width: 1, height: 1)
crossLayer.shadowRadius = 0;
crossLayer.shadowOpacity = 0.8
self.crossMarkLayer.path = path.cgPath
self.crossMarkLayer.position = CGPointMake(CGRectGetMinX(self.frame), CGRectGetMinY(self.frame))
self.crossMarkLayer.isHidden = false
return crossLayer
CATransaction.commit()
}
private func createAndShowStickBall(at center: CGPoint) -> CAShapeLayer {
// Create a circular path using UIBezierPath
let path = UIBezierPath(arcCenter: center, radius: 8, startAngle: 0, endAngle: 2 * .pi, clockwise: true)
private func createStickBall() -> CAShapeLayer {
// Create a CAShapeLayer
let stickBallLayer = CAShapeLayer()
stickBallLayer.path = path.cgPath // Assign the circular path to the shape layer
self.layer.superlayer?.addSublayer(stickBallLayer)
stickBallLayer.position = CGPointMake(CGRectGetMidX(self.crossMarkLayer.frame), CGRectGetMidY(self.crossMarkLayer.frame))
// stickBallLayer.position = CG
// Set the stroke color and width (border of the circle)
stickBallLayer.strokeColor = UIColor(red: 0.5, green: 0.5, blue: 1.0, alpha: 1.0).cgColor
//stickBallLayer.
@@ -625,9 +646,26 @@ import UIKit
// Set the fill color (inside of the circle)
stickBallLayer.fillColor = stickBallColor // Light fill with some transparency
stickBallLayer.isHidden = true
return stickBallLayer
}
private func showStickBall(at center: CGPoint) {
let path = UIBezierPath(arcCenter: center, radius: 8, startAngle: 0, endAngle: 2 * .pi, clockwise: true)
CATransaction.begin()
CATransaction.setDisableActions(true)
// Create a CAShapeLayer
self.stickBallLayer.path = path.cgPath // Assign the circular path to the shape layer
self.stickBallLayer.position = CGPointMake(CGRectGetMidX(self.crossMarkLayer.frame), CGRectGetMidY(self.crossMarkLayer.frame))
self.stickBallLayer.isHidden = false
CATransaction.commit()
}
@objc public func updateStickIndicator(){
CATransaction.begin()
@@ -653,8 +691,12 @@ import UIKit
CATransaction.commit()
}
private func resetStickBallPositionAndRemoveIndicator(){
private func resetStickBallPositionAndHideIndicator(){
CATransaction.begin()
CATransaction.setDisableActions(true)
handleStickBallLeavingBorder()
CATransaction.commit()
CATransaction.begin()
// CATransaction.setDisableActions(true)
CATransaction.setAnimationDuration(0.15)
@@ -665,8 +707,11 @@ import UIKit
usleep(200000)
DispatchQueue.main.async { // switch to main thread to update UI
if !self.touchBegan {
self.crossMarkLayer.removeFromSuperlayer()
self.stickBallLayer.removeFromSuperlayer()
CATransaction.begin()
CATransaction.setDisableActions(true)
self.crossMarkLayer.isHidden = true
self.stickBallLayer.isHidden = true
CATransaction.commit()
}
}
}
@@ -747,10 +792,10 @@ import UIKit
// show the indicator based on the touchBeganLocation
indicatorLayer.position = CGPointMake(CGRectGetMinX(self.frame)+touchBeganLocation.x, CGRectGetMinY(self.frame)+touchBeganLocation.y)
vibrationGenerator.prepare()
vibrationGenerator.impactOccurred()
print("vibrationInstance: \(vibrationGenerator)")
if vibrationOn {
vibrationGenerator.prepare()
vibrationGenerator.impactOccurred()
}
}
private func handleLrudTouchMove(){
@@ -1136,28 +1181,22 @@ import UIKit
if self.widgetType == WidgetTypeEnum.touchPad && touches.count == 1{ // don't use event?.allTouches?.count here, it will counts all touches including the ones captured by other UIViews
switch self.touchPadString {
case "LSPAD":
self.crossMarkLayer.removeFromSuperlayer()
self.stickBallLayer.removeFromSuperlayer()
self.l3r3Indicator.removeFromSuperlayer()
self.showStickIndicator()
if quickDoubleTapDetected {
self.l3r3Indicator = self.createAndShowl3r3Indicator()
self.showl3r3Indicator()
self.sendComboButtonsDownEvent(comboStrings: self.comboButtonStrings)}
case "RSPAD":
self.crossMarkLayer.removeFromSuperlayer()
self.stickBallLayer.removeFromSuperlayer()
self.l3r3Indicator.removeFromSuperlayer()
self.showStickIndicator()
if quickDoubleTapDetected {
self.l3r3Indicator = self.createAndShowl3r3Indicator()
self.showl3r3Indicator()
self.sendComboButtonsDownEvent(comboStrings: self.comboButtonStrings)}
case "LSVPAD":
if quickDoubleTapDetected {
self.l3r3Indicator = self.createAndShowl3r3Indicator()
self.showl3r3Indicator()
self.sendComboButtonsDownEvent(comboStrings: self.comboButtonStrings)}
case "RSVPAD":
if quickDoubleTapDetected {
self.l3r3Indicator = self.createAndShowl3r3Indicator()
self.showl3r3Indicator()
self.sendComboButtonsDownEvent(comboStrings: self.comboButtonStrings)}
case "DPAD", "WASDPAD", "ARROWPAD":
if allCapturedTouchesCount == 1 {showLrudBall(at: touchBeganLocation)}
@@ -1170,7 +1209,7 @@ import UIKit
}
case "DS4TOUCH":
if quickDoubleTapDetected {
self.l3r3Indicator = self.createAndShowl3r3Indicator()
self.showl3r3Indicator()
self.sendComboButtonsDownEvent(comboStrings: self.comboButtonStrings)
}
default:
@@ -1476,10 +1515,10 @@ import UIKit
switch self.touchPadString{
case "LSPAD":
self.onScreenControls.clearLeftStickTouchPadFlag()
if widgetType == WidgetTypeEnum.touchPad {self.resetStickBallPositionAndRemoveIndicator()}
if widgetType == WidgetTypeEnum.touchPad {self.resetStickBallPositionAndHideIndicator()}
case "RSPAD":
self.onScreenControls.clearRightStickTouchPadFlag()
if widgetType == WidgetTypeEnum.touchPad {self.resetStickBallPositionAndRemoveIndicator()}
if widgetType == WidgetTypeEnum.touchPad {self.resetStickBallPositionAndHideIndicator()}
case "LSVPAD":
self.onScreenControls.clearLeftStickTouchPadFlag()
case "RSVPAD":
@@ -1506,8 +1545,10 @@ import UIKit
}
}
self.l3r3Indicator.borderColor = UIColor.clear.cgColor
if CommandManager.stickTouchPads.contains(touchPadString){
self.l3r3Indicator.borderColor = UIColor.clear.cgColor
}
if CommandManager.directionPads.contains(touchPadString){
self.upIndicator.borderColor = UIColor.clear.cgColor
self.downIndicator.borderColor = UIColor.clear.cgColor
@@ -1560,8 +1601,6 @@ import UIKit
setupView(); //re-setup widgetView style
self.crossMarkLayer.removeFromSuperlayer()
self.stickBallLayer.removeFromSuperlayer()
if self.widgetType == WidgetTypeEnum.touchPad{
switch self.touchPadString{
case "LSPAD", "RSPAD":
@@ -91,7 +91,7 @@
- (void)reloadOnScreenWidgetViews{
NSLog(@"reloadOnScreenWidgets %f", CACurrentMediaTime());
OnScreenWidgetView.editMode = true;
[self clearStickIndicator];
[self hideStickIndicators];
for (UIView *subview in self.view.subviews) {
if ([subview isKindOfClass:[OnScreenWidgetView class]]) {
@@ -296,7 +296,7 @@
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator{
if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive) return;
viewWillBeResized = true;
[self clearStickIndicator];
[self hideStickIndicators];
if(!_quickSwitchEnabled) [self saveTapped:nil];
}
@@ -711,9 +711,15 @@
label.numberOfLines = 1;
}
- (void)clearStickIndicator{
[self->selectedWidgetView.stickBallLayer removeFromSuperlayer];
[self->selectedWidgetView.crossMarkLayer removeFromSuperlayer];
- (void)hideStickIndicators{
for(UIView* view in self.view.subviews){
if([view isKindOfClass:[OnScreenWidgetView class]]){
OnScreenWidgetView* widget = (OnScreenWidgetView* )view;
[widget.crossMarkLayer setHidden:true];
[widget.stickBallLayer setHidden:true];
}
}
}
/*
@@ -725,13 +731,13 @@
- (void)widgetViewTapped: (NSNotification *)notification{
//self.undoButton.alpha = selectedWidgetView.layoutChanges.count>1 && !CGPointEqualToPoint(selectedWidgetView.layoutChanges.lastObject.CGPointValue, selectedWidgetView.initialCenter)? 1.0 : 0.3;
[self hideStickIndicators];
// receive the selected widgetView obj passed from the notification
[self enableCommonWidgetTools];
OnScreenWidgetView* widgetView = (OnScreenWidgetView* )notification.object;
[self clearStickIndicator];
OnScreenWidgetView* widgetView = (OnScreenWidgetView* )notification.object;
self->widgetViewSelected = true;
self->controllerLayerSelected = false;
self->selectedWidgetView = widgetView;
@@ -775,7 +781,7 @@
}
if(showStickIndicatorOffsetStack){
// illustrating the indicator offset,
[self clearStickIndicator];
[self hideStickIndicators];
selectedWidgetView.touchBeganLocation = CGPointMake(CGRectGetWidth(selectedWidgetView.frame)/2, CGRectGetHeight(selectedWidgetView.frame)/4);
[selectedWidgetView showStickIndicator];// this will create the indicator CAShapeLayers
[self.stickIndicatorOffsetSlider setValue:self->selectedWidgetView.stickIndicatorOffset];
@@ -815,7 +821,7 @@
- (void)legacyOscLayerTapped: (NSNotification *)notification{
[self enableCommonWidgetTools];
CALayer* controllerLayer = (CALayer* )notification.object;
[self clearStickIndicator];
[self hideStickIndicators];
self->widgetViewSelected = false;
self->selectedWidgetView = nil;
@@ -1202,7 +1208,7 @@
- (void) presentProfilesTableView{
[self saveTapped:nil];
[self clearStickIndicator];
[self hideStickIndicators];
selectedWidgetView = nil;
UIStoryboard *storyboard;
BOOL isIPhone = ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone);
@@ -1329,7 +1335,7 @@
if(!isToolbarHidden && self->selectedWidgetView != nil && [self layerIsOverlappingWithTrashcanButton:selectedWidgetView.layer]){
[self->selectedWidgetView removeFromSuperview];
[self.onScreenWidgetViews removeObject:self->selectedWidgetView];
[self clearStickIndicator];
[self hideStickIndicators];
[selectedWidgetView.buttonDownVisualEffectLayer removeFromSuperlayer];
}