I have mapView to my ViewController in storyboard. It has 4 constraints ( Height equals: 300 , align trailing to: Safe Area, align Leading to: Safe Area and Align Top to: Safe Area. I created tapGestureRecognizer to my mapview. I want to resize mapview to full screen when user tap on a map.
private func setupMapView() {
let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(mapTouchAction(gestureRecognizer:)))
mapView.addGestureRecognizer(gestureRecognizer)
}
#objc func mapTouchAction(gestureRecognizer: UITapGestureRecognizer) {
}
I tried to change height constraint to screen Height but it is not what i want ( view is positioning in the middle of the screen and then its resizing , this is not what i am looking for) I used this code inside my mapTouchAction(). I want my view to resize with animation to the bottom view ( screen height). How can i achieve it? should i use CGAffineTransform or maybe theres another way? Any ideas?
for constraint in self.mapView.constraints {
if constraint.identifier == "mapViewHeightConstraintID" {
constraint.constant = UIScreen.main.bounds.height
}
}
UIView.animate(withDuration: 2, animations: {
self.mapView.layoutIfNeeded()
})
I found an easy solution for my problem. I only change my mapView frame. So inside tapGesture function mapTouchAction(_: UITapGestureRecognizer) i have
#objc func mapTouchAction(gestureRecognizer: UITapGestureRecognizer) {
UIView.animate(withDuration: 2, animations: {
self.mapView.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
self.mapView.layoutIfNeeded()
})
}
This code change my mapView height to UIScreen Height without with a nice resizing animation for 2 seconds.
Related
I'm trying to drag down a specific view to make the height go longer than before using UIPanGestureRecognizer. However, it keeps on going back to the normal size that i had initially programmed. The view that i'm trying to stretch keeps on shaking and goes back to the initial height. Any guesses why?
let CalendarDrag = UIPanGestureRecognizer(target: self, action: #selector(didDragCalendar))
lineView.isUserInteractionEnabled = true
lineView.addGestureRecognizer(CalendarDrag)
}
#objc func didDragCalendar(sender: UIPanGestureRecognizer) {
let velocity = sender.velocity(in: self.view) //속도
let translation = sender.translation(in: self.view) //위치
let height = self.topView.frame.maxY
if sender.state == .ended{
if velocity.y>0{
calendar.scope = .month
print("down")
}else{
calendar.scope = .week
print("up")
}
}else{
if height <= height+translation.y && height+translation.y <= height+230{
self.topView.frame = CGRect(x: 0, y: 0, width: self.topView.frame.width, height: height+translation.y)
UIView.animate(withDuration: 0, animations: {
self.view.layoutIfNeeded()
sender.setTranslation(CGPoint.zero, in: self.view)
})
}
}
}
For more information, I'm right now trying to make FSCalendar to show in "month" and "week" view according to the UIPanGesture that user make.
You are changing the frame height of your view. Don't do that.
Have an instance var to a height constraint, and change the constant value for that constraint. Then when you call layoutIfNeeded() from your animation, the constraint will change your height for you.
So I have two view and a button one of the view is hidden "View1" and the other is not "View2" , and once I click on the button "View1" will appear , but I want "View2" to go down , I will add image show what I want to do
Brute way, if your views has fix sizes:
1, create 3 variables for the position of the views
var view1Center: CGPoint = CGPoint(x: 100, y: 100)
var view2CenterBefore: CGPoint = CGPoint(x: 100, y: 100)
var view2CenterAfter: CGPoint = CGPoint(x: 100, y: 400)
2, In ViewDidLoad or ViewDidAppear set view's alpha to 0 and the positions
view1.alpha = 0
view2.alpha = 0
view1.center = view1Center
view2.center = view2CenterBefore
3, When you press the button, you should animate the moves and show view1.
#IBAction func showView1(_ sender: Any) {
UIView.animate(withDuration: 0.5, animations: {
view2.center = view2CenterAfter
})
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
UIView.animate(withDuration: 0.5, animatios: {
view1.alpha = 1
}
}
}
We can use UIStackView class for this with ease. We can add both the views in a UIStackView instance with vertical axis. view1 height should have Highest constraint priority (999) instead of required (1000). This way when view1 is hidden, it's height constraint won't have conflict.
You can take reference of following code snippet:
let stack = UIStackView()
// aligns subviews in top to bottom manner
stack.axis = .vertical
stack.addArrangedSubview(view1)
stack.addArrangedSubview(view2)
When view1 is kept hidden, view2 will automatically move up. StackView should not be given height constraint so that it will have inferred height of summation of its subviews.
I have an image view that pops up in the centre of the screen. You can pinch to zoom in or zoom out the image as well as move it horizontally. All these actions work perfectly. However I want to restrict the panning movements so users can't swipe beyond the left or right edges of the image. Below Ive posted screenshots along with explanations to show what I mean
Original View
Image moved to the right. At the moment you can see you can move it beyond the left edge of the image and it show black a black space. If the image width is equal to the screen width then I obviously want the pan gesture to be disable
Image zoomed in
Imaged moved to the left but again I want to be able to restrict the pan gesture to the edge of the image so there is no black space on the right of the image.
Ive tried looking around but I can't find anything that can help with my specific problem. Ive posted my code below. Any help would be much appreciated! Thanks in advance
func handlePan(_ gestureRecognizer: UIPanGestureRecognizer) {
guard let zoomView = gestureRecognizer.view else{return}
if gestureRecognizer.state == UIGestureRecognizerState.began || gestureRecognizer.state == UIGestureRecognizerState.changed {
let translation = gestureRecognizer.translation(in: self.view)
if(gestureRecognizer.view!.center.x < 300) {
gestureRecognizer.view!.center = CGPoint(x:gestureRecognizer.view!.center.x + translation.x, y: gestureRecognizer.view!.center.y)
}else{
gestureRecognizer.view!.center = CGPoint(x:299, y: gestureRecognizer.view!.center.y)
}
gestureRecognizer.setTranslation(CGPoint.zero, in: zoomView)
}
}
I followed this youtube video to get it done.
I can't help you with the zoom but I can help you stop the imageView from moving outside of the left and right sides when NOT zooming.
You didn't give any context as to wether or not your imageView was created in Storyboard or programmatically. The one in my example is programmatic and it's named orangeImageView.
Create a new project then just copy and paste this code inside of the View Controller. When you run the project you will see an orange imageView that you can move around but it won't go beyond the left or right side of the screen. I didn't bother with the top or bottom because it wasn't part of your question.
Follow Steps 1 - 8 inside #objc func panGestureHandler(_ gestureRecognizer: UIPanGestureRecognizer) for an explanation of what each step does and how it works.
Replace the orangeImageView with the imageView your using:
class ViewController: UIViewController {
// create frame in viewDidLoad
let orangeImageView: UIImageView = {
let imageView = UIImageView()
imageView.isUserInteractionEnabled = true
imageView.backgroundColor = .orange
return imageView
}()
var panGesture: UIPanGestureRecognizer!
override func viewDidLoad() {
super.viewDidLoad()
// create a frame for the orangeImageView and add it as a subview
orangeImageView.frame = CGRect(x: 50, y: 50, width: 100, height: 100)
view.addSubview(orangeImageView)
// initialize the pangesture and add it to the orangeImageView
panGesture = UIPanGestureRecognizer(target: self, action: #selector(panGestureHandler(_:)))
orangeImageView.addGestureRecognizer(panGesture)
}
#objc func panGestureHandler(_ gestureRecognizer: UIPanGestureRecognizer){
// 1. use these values to restrict the left and right sides so the orangeImageView won't go beyond these points
let leftSideRestrction = self.view.frame.minX
let rightSideRestriction = self.view.frame.maxX
// 2. use these values to redraw the orangeImageView's correct size in either Step 6 or Step 8 below
let imageViewHeight = self.orangeImageView.frame.size.height
let imageViewWidth = self.orangeImageView.frame.size.width
if gestureRecognizer.state == .changed || gestureRecognizer.state == .began {
let translation: CGPoint = gestureRecognizer.translation(in: self.view)
gestureRecognizer.view!.center = CGPoint(x: gestureRecognizer.view!.center.x + translation.x, y: gestureRecognizer.view!.center.y + translation.y)
gestureRecognizer.setTranslation(CGPoint.zero, in: self.view)
/*
3.
-get the the upper left hand corner of the imageView's X and Y origin to get the current location of the imageView as it's dragged across the screen.
-you need the orangeImageView.frame.origin.x value to make sure it doesn't go beyond the left or right edges
-you need the orangeImageView.frame.origin.y value to redraw it in Steps 6 and 8 at whatever Y position it's in when it hits either the left or right sides
*/
let imageViewCurrentOrginXValue = self.orangeImageView.frame.origin.x
let imageViewCurrentOrginYValue = self.orangeImageView.frame.origin.y
// 4. get the right side of the orangeImageView. It's computed using the orangeImageView.frame.origin.x + orangeImageView.frame.size.width
let imageViewRightEdgePosition = imageViewCurrentOrginXValue + imageViewWidth
// 5. if the the orangeImageView.frame.origin.x touches the left edge of the screen or beyond it proceed to Step 6
if imageViewCurrentOrginXValue <= leftSideRestrction {
// 6. redraw the orangeImageView's frame with x: being the far left side of the screen and Y being where ever the current orangeImageView.frame.origin.y is currently positioned at
orangeImageView.frame = CGRect(x: leftSideRestrction, y: imageViewCurrentOrginYValue, width: imageViewWidth, height: imageViewHeight)
}
// 7. if the the orangeImageView.frame.origin.x touches the right edge of the screen or beyond it proceed to Step 8
if imageViewRightEdgePosition >= rightSideRestriction{
// 8. redraw the orangeImageView's frame with x: being the rightSide of the screen - the orangeImageView's width and y: being where ever the current orangeImageView.frame.origin.y is currently positioned at
orangeImageView.frame = CGRect(x: rightSideRestriction - imageViewWidth, y: imageViewCurrentOrginYValue, width: imageViewWidth, height: imageViewHeight)
}
}
}
}
Im having abit of trouble animating a label to move into another position when a user scrolls horizontally.
Here is the snippet i have:
override func viewDidLoad() {
super.viewDidLoad()
buttonTextSpacing(UIButton: vysionButton, lineSpacing: 2.5, UIColor: .black)
buttonTextSpacing(UIButton: converseButton, lineSpacing: 2.5, UIColor: .black)
buttonTextSpacing(UIButton: storiesButton, lineSpacing: 2.5, UIColor: .black)
self.storiesCollectionView.delegate = self
self.storiesCollectionView.dataSource = self
// Scroll View
self.scrollView.contentSize = CGSize(width: self.scrollView.frame.width*2, height: self.scrollView.frame.height)
self.scrollView.addSubview(storiesCollectionView)
self.scrollView.showsHorizontalScrollIndicator = false
self.scrollView.delegate = self
}
func scrollViewDidScroll(scrollUIView: UIScrollView) {
print("scrollViewDidScroll")
DispatchQueue.main.async {
UIView.animate(withDuration: 0.4, delay: 0, options: UIViewAnimationOptions.curveEaseOut, animations: {
self.scrollLabel.center.x = self.storiesButton.center.x - 1
}, completion: nil)
}
}
Basically what im trying to achieve is that when a user scrolls, the animation starts but does not finish until the scroll is finished to the next custom uiview (I have paging enabled also).
Currently it doesnt do that, im not able to call the scrolling event nor even make the label animate (To the new position) while scrolling.
Many thanks in advance for any advice or help.
Cheers,
Pon
As I understand you have some label as subview on scrollView and that label is located over some views that you scroll. You may use scrollView.contentOffset.x instead of animation. For example: You need to calculate the distance between the start position of label and end position. That distance divide by 100, you get step (1 percent of distance width) that you need to multiply by scrollView.contentOffset.x. Give more details of your question.
I have a label on a imageview and both of them are in one view. The label is pinch-able via below code. However, it is pinch-able also out of image view. I want the areas outside of the imageview not seen (like in whatsapp or snapchat. The texts outside of the screen is not seen, i want that for only imageview area). I'm not sure but i guess somehow it will be done with bring view to front function. Just i don't know how to do it
func handlePinch(recognizer: UIPinchGestureRecognizer) {
if let view = recognizer.view as? UILabel {
let pinchScale: CGFloat = recognizer.scale
view.transform = view.transform.scaledBy(x: pinchScale, y: pinchScale)
recognizer.scale = 1.0
}
}
I done it with creating views out of imageview (left, right upper and bottom side) and set all views to the front except the view which has imageview. I created the first three view in (left, right and the bottomside) in the storyboard and last one (the upper one) in the code because i needed to hide status bar first then create a view on top of it.
customView = UIView(frame: CGRect(x: 0, y: 0, width: 440, height: 20))
customView.backgroundColor = UIColor.white
self.view.addSubview(customView)
self.view.bringSubview(toFront: view_main)
self.view.bringSubview(toFront: view2)
self.view.bringSubview(toFront: view3)
self.view.bringSubview(toFront: customView)