reduce on-screen widget visual effect performance cost

This commit is contained in:
TrueZhuanjia committed 2025-08-27 22:35:47 +08:00
1 parent 6bae985e2c
commit 49ed0e43e9
2 files changed
+111 -66

No files matched your search

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