Reputation: 194
I am trying to build a drag drop action and if I drag a view from stack view and drop it to somewhere and remove the view with "removeArrangedSubview" it changes the dragged items size and makes it bigger. I am using this piece of code to resize dropped item.
sender.view!.frame = CGRectMake(sender.view!.frame.origin.x, sender.view!.frame.origin.y, sender.view!.frame.width * 0.5, sender.view!.frame.height * 0.5)
Here is the image for the comparison.
Upvotes: 0
Views: 2682
Reputation: 15331
You are setting the frame of the view you are moving but when you place it in a stack view the stack view will reset it based on the stack view's constraints and the intrinsic content size of the view that you are adding to it. The reason it is not doing that when you don't call removeArrangedSubview
is because it has not triggered an auto layout pass. In general, when you're using auto layout you shouldn't set views frames but rather update constraints intrinsicContentSize
and request auto layout updates.
You should play around with the distribution
property of your stack view, the constraints you have placed on it, as well as the intrinsicContentSize
of the views you are adding to it until you get your desired result.
For example:
class ViewController: UIViewController
{
let stackView = UIStackView()
let otherStackView = UIStackView()
override func viewDidLoad()
{
self.view.backgroundColor = UIColor.whiteColor()
stackView.alignment = .Center
stackView.axis = .Horizontal
stackView.spacing = 10.0
stackView.distribution = .FillEqually
stackView.translatesAutoresizingMaskIntoConstraints = false
otherStackView.alignment = .Center
otherStackView.axis = .Horizontal
otherStackView.spacing = 10.0
otherStackView.distribution = .FillEqually
otherStackView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(stackView)
self.view.addSubview(otherStackView)
stackView.bottomAnchor.constraintEqualToAnchor(self.view.bottomAnchor).active = true
stackView.leadingAnchor.constraintEqualToAnchor(self.view.leadingAnchor).active = true
stackView.trailingAnchor.constraintEqualToAnchor(self.view.trailingAnchor).active = true
stackView.heightAnchor.constraintEqualToConstant(150).active = true
otherStackView.topAnchor.constraintEqualToAnchor(self.view.topAnchor).active = true
otherStackView.widthAnchor.constraintGreaterThanOrEqualToConstant(50).active = true
otherStackView.centerXAnchor.constraintEqualToAnchor(self.view.centerXAnchor).active = true
otherStackView.heightAnchor.constraintEqualToConstant(150).active = true
self.addSubviews()
}
func addSubviews()
{
for _ in 0 ..< 5
{
let view = View(frame: CGRect(x: 0.0, y: 0.0, width: 100, height: 100))
view.userInteractionEnabled = true
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(self.panHandler(_:)))
view.addGestureRecognizer(panGesture)
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = UIColor.redColor()
self.stackView.addArrangedSubview(view)
}
}
func panHandler(sender: UIPanGestureRecognizer)
{
guard let view = sender.view else{ return }
switch sender.state {
case .Began:
self.stackView.removeArrangedSubview(view)
self.view.addSubview(view)
let location = sender.locationInView(self.view)
view.center = location
case .Changed:
view.center.x += sender.translationInView(self.view).x
view.center.y += sender.translationInView(self.view).y
case .Ended:
if CGRectContainsPoint(self.otherStackView.frame, view.center)
{
self.otherStackView.addArrangedSubview(view)
self.otherStackView.layoutIfNeeded()
}
else
{
self.stackView.addArrangedSubview(view)
self.otherStackView.layoutIfNeeded()
}
default:
self.stackView.addArrangedSubview(view)
self.otherStackView.layoutIfNeeded()
}
sender.setTranslation(CGPointZero, inView: self.view)
}
}
class View: UIView
{
override func intrinsicContentSize() -> CGSize
{
return CGSize(width: 100, height: 100)
}
}
The above view controller and UIView
subclass does something similar to what you're looking for, but it's not possible to tell from your question. Notice that pinning a stack view to the edges of its super view (like stackView
) causes it to stretch subviews to fill all the available space while allowing the stack view to dynamically size based on the intrinsic size of its subviews (like otherStackView
) does not.
If you don't want to add the view to another stack view but you want them to retain their frame, you should remove any constraints the view's have on them and then set their translatesAutoresizingMaskIntoConstraints
property to true
. For example:
func panHandler(sender: UIPanGestureRecognizer)
{
guard let view = sender.view else{ return }
switch sender.state {
case .Began:
self.stackView.removeArrangedSubview(view)
self.view.addSubview(view)
let location = sender.locationInView(self.view)
view.center = location
case .Changed:
view.center.x += sender.translationInView(self.view).x
view.center.y += sender.translationInView(self.view).y
default:
view.removeConstraints(view.constraints)
view.translatesAutoresizingMaskIntoConstraints = true
// You can now set the view's frame or position however you want
view.center.x += sender.translationInView(self.view).x
view.center.y += sender.translationInView(self.view).y
}
sender.setTranslation(CGPointZero, inView: self.view)
}
Upvotes: 1