Swift中UIPanGesture仅左右生效,上下滑动失效问题排查
问题描述
开发一款卡牌游戏,布局包含7×7主网格,以及主网格北、东、南、西四个方向的3×7侧边网格。计划通过UIPanGesture实现侧边卡牌的滚动,但添加右侧卡牌后,手势仅支持左右滑动,上下滑动功能失效。排查发现arrayAllCards.append(button)这行代码导致南北方向的手势无法正常工作。
相关代码
创建右侧卡牌的循环代码
for j in 0...6{ for i in 0...3 { let image = UIImage(named: arrayShuffle[(i+1)*(j+1)].suitRank) as UIImage? var cardPos: [Int] = [] cardPos.append(j) cardPos.append(7+i) var button = Card(suitRank: arrayShuffle[(i+1)*(j+1)].suitRank, position: cardPos, suit: arrayShuffle[(i+1)*(j+1)].suit, rank: arrayShuffle[(i+1)*(j+1)].rank, x: cardPos[0] * (Int(screensize)/7), y: cardPos[1] * (Int(screensize)/7), isChosen: false) arrayShuffle.remove(at: (i+1)*(j+1)) let valueX = Int(CGFloat(0 + (i * sizeButton))) let valueY = Int(CGFloat(middlepos - CGFloat(sizeButton * j))) button.frame = CGRect(x: valueX, y: valueY, width: sizeButton, height: sizeButton) button.backgroundColor = .red button.configuration?.imagePadding = 0 button.setImage(image, for: .normal) button.contentVerticalAlignment = .fill button.contentHorizontalAlignment = .fill arrayAllCards.append(button) button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside) let scrollGesture = UITapGestureRecognizer(target: self, action: #selector(swipeUp)) button.isUserInteractionEnabled = false view.addSubview(button) view.addGestureRecognizer(scrollGesture) } }
UIPanGesture处理代码
@objc func swipeUp(_ gesture: UIPanGestureRecognizer) { var vertical: Bool = false let moveDirection = gesture.translation(in: self.view) if (abs(moveDirection.x) < abs(moveDirection.y)){ vertical = true } let result = UIPanGestureRecognizer.State.ended.rawValue var screenRealEstate: Int = (Int) (self.screenheight - self.screensize) / 2 screenRealEstate -= (Int)(screensize) / 7 * 2 var stoppage: Bool = false for i in arrayAllCards { let translation = gesture.translation(in: self.view) let value1 : Int = Int(arrayAllCards[90].center.y) let value: Int = (self.origin + 7 * buttonSize) - 3 * self.buttonSize let value2: Int = (self.origin + 13 * buttonSize) let value3 : Int = Int(arrayAllCards[90].center.x) let value4 : Int = 4 * self.buttonSize let value5 : Int = 10 * self.buttonSize if(value3 > value4 && value3 < value5 && !vertical){ i.center.x = translation.x/10 + i.center.x } if(value1 > value && value1 < value2 && vertical){ i.center.y = translation.y/10 + i.center.y // Customize this. } if(gesture.state.rawValue == 3){ UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseOut, animations: { for k in 0..<self.arrayAllCards.count { self.arrayAllCards[k].center.x = CGFloat(self.arrayAllCards[k].position[1]) * CGFloat(self.buttonSize) + CGFloat(self.buttonSize/2) self.arrayAllCards[k].center.y = CGFloat((Int)(self.origin)) + CGFloat(self.arrayAllCards[k].position[0] * self.buttonSize) + CGFloat(self.buttonSize/2) } }, completion: { finished in } )} } }
问题分析与修复方案
核心问题点
- 手势类型错误:代码中用
UITapGestureRecognizer(点击手势)处理滑动操作,完全不符合需求,应该使用UIPanGestureRecognizer(平移手势)。 - 手势重复添加:循环里每创建一个按钮就给view加一次手势,导致view上堆叠大量重复手势,引发冲突。
- 数组与判断逻辑绑定错误:所有侧边卡牌放入同一数组后,手势处理用固定索引
arrayAllCards[90]的位置做判断,该索引可能越界,且南北侧卡牌位置不满足条件,导致上下滑动无响应。 - 统一遍历逻辑混乱:不分方向遍历所有卡牌,滑动方向与对应侧边卡牌的匹配逻辑错位,只有东侧卡牌符合左右滑动判断,南北侧卡牌无法触发上下滑动。
修复步骤
- 替换手势类型并统一添加
删除循环内添加手势的代码,在viewDidLoad中仅添加一次平移手势:
override func viewDidLoad() { super.viewDidLoad() // 其他初始化代码... let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan)) view.addGestureRecognizer(panGesture) }
- 拆分侧边卡牌数组
为四个方向的卡牌分别创建数组,方便区分处理:
var northCards: [Card] = [] var eastCards: [Card] = [] var southCards: [Card] = [] var westCards: [Card] = []
创建对应方向卡牌时,将按钮加入对应数组,而非统一放入arrayAllCards。
- 修正手势处理逻辑
重命名原swipeUp方法为handlePan,根据滑动方向操作对应数组的卡牌:
@objc func handlePan(_ gesture: UIPanGestureRecognizer) { let translation = gesture.translation(in: view) let vertical = abs(translation.y) > abs(translation.x) if vertical { // 垂直滑动:操作南北侧卡牌 adjustVerticalCards(translation: translation) } else { // 水平滑动:操作东西侧卡牌 adjustHorizontalCards(translation: translation) } if gesture.state == .ended { resetAllCards() } gesture.setTranslation(.zero, in: view) } // 调整垂直方向卡牌位置 private func adjustVerticalCards(translation: CGPoint) { let offset = translation.y * 0.1 northCards.forEach { $0.center.y += offset } southCards.forEach { $0.center.y += offset } } // 调整水平方向卡牌位置 private func adjustHorizontalCards(translation: CGPoint) { let offset = translation.x * 0.1 eastCards.forEach { $0.center.x += offset } westCards.forEach { $0.center.x += offset } } // 复位所有卡牌到初始位置 private func resetAllCards() { UIView.animate(withDuration: 0.3) { [self.northCards, self.eastCards, self.southCards, self.westCards].forEach { cards in cards.forEach { card in card.center = CGPoint( x: CGFloat(card.position[1]) * self.buttonSize + self.buttonSize/2, y: CGFloat(self.origin) + CGFloat(card.position[0]) * self.buttonSize + self.buttonSize/2 ) } } } }
- 移除错误索引判断
删掉原代码中依赖arrayAllCards[90]的位置判断,改为根据卡牌所属数组区分处理,确保不同方向卡牌能响应对应滑动操作。
内容的提问来源于stack exchange,提问作者cosmopolice
相关产品推荐
相关产品推荐

