【发布时间】:2021-03-04 14:17:17
【问题描述】:
我有 3 个水平的 UIStackViews(我们称它们为 labelStackViews),其中包含许多 UILabel。 所有 3 个视图都在另一个水平 StackView 内(我们称之为 mainStackView)。
我希望能够通过用手指拖动标签将标签从一个 labelStackView 移动到另一个。
我使用 createPanGestureRecognizer 使每个标签都可移动。 因此,如果我在另一个 labelStackView 的边界内拖动一个标签,我希望它切换位置。
但我在从一个视图到另一个视图中删除和添加标签时遇到问题。
每个堆栈视图内的标签图像。 “-3x”、“+2x”是stackview 1中的标签,“=”在stackview 2中,“2”、“+3”、“+4”在stackview 3中
这是我使用的代码,当我观察到标签放在另一个 labelStackView 上方时:
lableStackView1.removeArrangedSubview(label1)
labelStackView1.setNeedsLayout()
labelStackView1.layoutIfNeeded()
labelStackView3.addArrangedSubview(label1)
labelStackView3.setNeedsLayout()
结果是,label1 完全从屏幕上消失了。 并且 labelStackView1 中的其他标签按比例放大以填充整个 labelStackView 1。
我尝试将这些代码行移到 DispatchQueue.main.async {} 中。 但这并没有帮助。
我将这 3 个 labelStackViews 放在另一个 StackView 中的原因是自动缩放每个标签并将标签很好地放在一起。
如果它有所作为,这是我对 labelStackViews 的限制:
labelStackView.axis = NSLayoutConstraint.Axis.horizontal
labelStackView.distribution = UIStackView.Distribution.fillProportionally
labelStackView.alignment = UIStackView.Alignment.center
labelStackView.spacing = 5.0
在 UILabels 上:
label.textAlignment = .center
label.layer.masksToBounds = true
label.numberOfLines = 1
label.adjustsFontSizeToFitWidth = true
label.sizeToFit()
label.layoutIfNeeded()
提前感谢您的帮助,我尝试了很多不同的东西,但我对 swift 有点陌生,所以也许我遗漏了一些明显的东西。
...这是完整的代码:
import UIKit
class imageViewController: UIViewController {
@IBOutlet weak var upperLabel: UILabel!
@IBOutlet weak var lowerLabel: UILabel!
@IBOutlet weak var screenStackView: UIStackView!
let labelStackView1 = UIStackView()
let labelStackView2 = UIStackView()
let labelStackView3 = UIStackView()
let label1 = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 21))
let label2 = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 21))
let label3 = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 21))
let equalSign = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 21))
var labels: [UILabel] = []
var oldPos: [CGPoint] = [CGPoint(x: 0,y: 0), CGPoint(x: 0,y: 0), CGPoint(x: 0,y: 0)]
var oldPosInView: [CGPoint] = [CGPoint(x: 0,y: 0), CGPoint(x: 0,y: 0), CGPoint(x: 0,y: 0)]
var side: [String] = []
var equalPos: CGPoint = CGPoint(x: 0,y: 0)
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = hexStringToUIColor(hex: "#93DDFA")
labels = [label1, label2, label3]
//Add first stackview to screen and then add labels to stackview
initStackView(sview: labelStackView1)
initLabel(label: labels[0], text: "2x", stackView: labelStackView1)
side.append("Left")
initLabel(label: labels[1], text: "+3", stackView: labelStackView1)
side.append("Left")
initStackView(sview: labelStackView2)
initLabel(label: equalSign, text: "=", stackView: labelStackView2)
initStackView(sview: labelStackView3)
initLabel(label: labels[2], text: "-4x", stackView: labelStackView3)
side.append("Right")
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
updatePositions(labelsInStackView: labels, stackViewScreen: screenStackView)
createPanGestureRecognizer(labels: labels)
}
func updatePositions(labelsInStackView: [UILabel], stackViewScreen: UIStackView) {
for (ind, label) in labels.enumerated() {
oldPos[ind] = getConvertedPoint(label, baseView: view)
oldPosInView[ind] = label.frame.origin
}
equalPos = getConvertedPoint(equalSign, baseView: view)
}
//Create moving gesture for all objects
func createPanGestureRecognizer(labels: [UILabel]) {
for label in labels {
let gesture = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(panGesture:)))
label.addGestureRecognizer(gesture)
label.isUserInteractionEnabled = true
}
}
//Move the object and deside what to do when the action ends
@objc func handlePanGesture(panGesture: UIPanGestureRecognizer) {
// get translation
let translation = panGesture.translation(in: view)
panGesture.setTranslation(CGPoint(x: 0.0, y: 0.0), in: view)
if let myView = panGesture.view {
myView.center = CGPoint(x: myView.center.x + translation.x, y: myView.center.y + translation.y)
myView.isUserInteractionEnabled = true
}
//Move objects back to equation when action ends
if (panGesture.state == UIGestureRecognizer.State.ended) {
for (ind, label) in labels.enumerated() {
let newPos = getConvertedPoint(label, baseView: view)
if (newPos.x != oldPos[ind].x) || (newPos.y != oldPos[ind].y) {
//If the object moved side then change sign and move other objects
if didLabelMoveSide(ind: ind) {
print("It moved side")
labelMovedSide(leftStackView: labelStackView1, middleStackView: labelStackView2, rightStackView: labelStackView1, view: view, ind: ind)
break
} else {
print("It did not move side")
labelNotMovedSide(leftStackView: labelStackView1, middleStackView: labelStackView2, rightStackView: labelStackView3, view: view, ind: ind)
}
}
}
updatePositions(labelsInStackView: labels, stackViewScreen: screenStackView)
}
}
}
extension imageViewController {
func didLabelMoveSide(ind: Int) -> Bool {
let newP = getConvertedPoint(labels[ind], baseView: view)
let equalSignPos = equalPos.x
if (newP.x > equalSignPos &&
oldPos[ind].x <= equalSignPos) ||
(newP.x <= equalSignPos && oldPos[ind].x > equalSignPos) {
return true
} else {
return false
}
}
func labelNotMovedSide(leftStackView: UIStackView, middleStackView: UIStackView, rightStackView: UIStackView, view: UIView, ind: Int) {
self.labels[ind].frame.origin = oldPosInView[ind]
}
func labelMovedSide(leftStackView: UIStackView, middleStackView: UIStackView, rightStackView: UIStackView, view: UIView, ind: Int) {
//Laben "ind" is moving side
//Remove it from on view and add it to another
DispatchQueue.main.async {
if self.side[ind] == "Left" {
self.labelStackView1.removeArrangedSubview(self.labels[ind])
self.labelStackView1.setNeedsLayout()
self.labelStackView1.layoutIfNeeded()
self.labelStackView3.addArrangedSubview(self.labels[ind])
self.labelStackView3.setNeedsLayout()
self.side[ind] = "Right"
} else {
self.labelStackView3.removeArrangedSubview(self.labels[ind])
self.labelStackView3.setNeedsLayout()
self.labelStackView3.layoutIfNeeded()
self.labelStackView1.addArrangedSubview(self.labels[ind])
self.labelStackView1.setNeedsLayout()
self.side[ind] = "Left"
}
}
}
func initLabel(label: UILabel, text: String, stackView: UIStackView) {
label.text = text
label.font = UIFont(name: "San Francisco", size: 40)
label.textColor = hexStringToUIColor(hex: "#1C3294")
label.font = UIFont.boldSystemFont(ofSize: K.textSize)
label.textAlignment = .center
label.layer.masksToBounds = true
label.frame.size.width = label.intrinsicContentSize.width
label.frame.size.height = label.intrinsicContentSize.height
label.layer.borderColor = UIColor.white.cgColor
label.layer.borderWidth = 6.0
label.layer.masksToBounds = true
label.numberOfLines = 1
label.adjustsFontSizeToFitWidth = true
label.sizeToFit()
label.layoutIfNeeded()
stackView.addArrangedSubview(label)
}
func initStackView(sview: UIStackView) {
sview.axis = NSLayoutConstraint.Axis.horizontal
sview.distribution = UIStackView.Distribution.fillProportionally
sview.alignment = UIStackView.Alignment.center
sview.spacing = 5.0
screenStackView.addArrangedSubview(sview)
}
func getConvertedPoint(_ targetView: UIView, baseView: UIView)->CGPoint{
var pnt = targetView.frame.origin
if nil == targetView.superview{
return pnt
}
var superView = targetView.superview
while superView != baseView{
pnt = superView!.convert(pnt, to: superView!.superview)
if nil == superView!.superview{
break
}else{
superView = superView!.superview
}
}
return superView!.convert(pnt, to: baseView)
}
}
【问题讨论】:
-
显示您当前用于尝试拖动/移动标签的代码。提示:为您的标签提供不同的背景颜色,以便更轻松地查看内容。此外,当您开始拖动标签时,您究竟想要发生什么?当您在标签上拖动时,该标签占用的空间是否应该“折叠”然后在标签之间“出现”空白空间?还是别的什么?
-
是的,我已经编辑了我的问题并添加了完整的代码,所以现在您可以看到我可以拖动标签的代码。是的,确切地说,当我移动标签时会发生您所描述的情况,但我的项目还没有那么远。
标签: swift uilabel uistackview