make UIImageView fall - ios

I've UIImageview with its own position, after clicking that ( done with tapgesture ) I want that view to fall to ground until the position is 0. I tried making it with while loop but doesn't seem to work. any soltuions ?
var bananaView = UIImageView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
#objc func handleTap(_ sender:UITapGestureRecognizer) {
let centerPosition = bananaView.frame.origin.y
while centerPosition >= 0 {
bananaView.layer.position = CGPoint(x: 0,y : centerPosition - 1)
}
}

You set the new position (0) for it. Then you wrap the layout update inside an animation block
#objc func handleTap(_ sender:UITapGestureRecognizer) {
let centerPosition = bananaView.frame.origin.y
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { timer in
if bananaView.frame.origin.y - bananaView.frame.height == 0 {
timer.invalidate()
} else {
bananaView.frame.origin.y -= 1
}
}
}

Related

iOS Spin UIImageView with deceleration motion at random position

I trying to create a spin wheel which rotate on tap and it rotates for certain period of time and stops at some random circular angle.
import UIKit
class MasterViewController: UIViewController {
lazy var imageView: UIImageView = {
let bounds = self.view.bounds
let v = UIImageView()
v.backgroundColor = .red
v.frame = CGRect(x: 0, y: 0,
width: bounds.width - 100,
height: bounds.width - 100)
v.center = self.view.center
return v
}()
lazy var subView: UIView = {
let v = UIView()
v.backgroundColor = .black
v.frame = CGRect(x: 0, y: 0,
width: 30,
height: 30)
return v
}()
var dateTouchesEnded: Date?
var dateTouchesStarted: Date?
var deltaAngle = CGFloat(0)
var startTransform: CGAffineTransform?
var touchPointStart: CGPoint?
override func viewDidLoad() {
super.viewDidLoad()
self.imageView.addSubview(self.subView)
self.view.addSubview(self.imageView)
self.imageView.isUserInteractionEnabled = true
self.setupGesture()
}
private func setupGesture() {
let gesture = UITapGestureRecognizer(target: self,
action: #selector(handleGesture(_:)))
self.view.addGestureRecognizer(gesture)
}
#objc
func handleGesture(_ sender: UITapGestureRecognizer) {
var timeDelta = 1.0
let _ = Timer.scheduledTimer(withTimeInterval: 0.2,
repeats: true) { (timer) in
if timeDelta < 0 {
timer.invalidate()
} else {
timeDelta -= 0.03
self.spinImage(timeDelta: timeDelta)
}
}
}
func spinImage(timeDelta: Double) {
print("TIME DELTA:", timeDelta)
let direction: Double = 1
let rotation: Double = 1
UIView.animate(withDuration: 5,
delay: 0,
options: .curveEaseOut,
animations: {
let transform = self.imageView.transform.rotated(
by: CGFloat(direction) * CGFloat(rotation) * CGFloat(Double.pi)
)
self.imageView.transform = transform
}, completion: nil)
}
}
I tried via above code, but always stops on initial position
i.e. the initial and final transform is same.
I want it to be random at every time.
One thing you can do is make a counter with a random number within a specified range. When the time fires, call spinImage then decrement the counter. Keep doing that until the counter reaches zero. This random number will give you some variability so that you don't wind up with the same result every time.
#objc func handleGesture(_ sender: UITapGestureRecognizer) {
var counter = Int.random(in: 30...33)
let _ = Timer.scheduledTimer(withTimeInterval: 0.2, repeats: true) { (timer) in
if counter < 0 {
timer.invalidate()
} else {
counter -= 1
self.spinImage()
}
}
}
In spinImage, instead of rotating by CGFloat.pi, rotate by by CGFloat.pi / 2 so that you have four possible outcomes instead of two.
func spinImage() {
UIView.animate(withDuration: 2.5,
delay: 0,
options: .curveEaseOut,
animations: {
let transform = self.imageView.transform.rotated(
by: CGFloat.pi / 2
)
self.imageView.transform = transform
}, completion: nil)
}
You may want to mess around with the counter values, the timer interval, and the animation duration to get the effect that you want. The values I chose here are somewhat arbitrary.

How to create swipe to start button with moving arrows

I want to create the exactly the same swipe button like this https://github.com/shadowfaxtech/proSwipeButton .
I was wondering how to change the arrow of the button on user touches
I was doing this for getting swipe action.
let rightSwipe = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipes(_:)))
rightSwipe.direction = .right
view.addGestureRecognizer(rightSwipe)
but the thing is how to add arrows to button which change there position on user touches.
Here is the code I have written for swiping over the button. You assign image to the image view.
func createSwipeButton() {
let button = UIButton.init(type: .custom)
button.backgroundColor = UIColor.brown
button.setTitle("PLACE ORDER", for: .normal)
button.frame = CGRect.init(x: 10, y: 200, width: self.view.frame.size.width-20, height: 100)
button.addTarget(self, action: #selector(swiped(_:event:)), for: .touchDragInside)
button.addTarget(self, action: #selector(swipeEnded(_:event:)), for: .touchUpInside)
self.view.addSubview(button)
let swipableView = UIImageView.init()
swipableView.frame = CGRect.init(x: 0, y: 0, width: 20, height: button.frame.size.height)
swipableView.tag = 20
swipableView.backgroundColor = UIColor.white
button.addSubview(swipableView)
}
#objc func swiped(_ sender : UIButton, event: UIEvent) {
let swipableView = sender.viewWithTag(20)!
let centerPosition = location(event: event, subView: swipableView, superView: sender,isSwiping: true)
UIView.animate(withDuration: 0.2) {
swipableView.center = centerPosition
}
}
#objc func swipeEnded(_ sender : UIButton, event: UIEvent) {
let swipableView = sender.viewWithTag(20)!
let centerPosition = location(event: event, subView: swipableView, superView: sender, isSwiping: false)
UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 5, options: .curveEaseInOut, animations: {
swipableView.center = centerPosition
}) { _ in}
}
func location(event: UIEvent, subView: UIView, superView: UIButton, isSwiping: Bool) -> CGPoint {
if let touch = event.touches(for: superView)?.first{
let previousLocation = touch.previousLocation(in: superView)
let location = touch.location(in: superView)
let delta_x = location.x - previousLocation.x;
print(subView.center.x + delta_x)
var centerPosition = CGPoint.init(x: subView.center.x + delta_x, y: subView.center.y)
let minX = subView.frame.size.width/2
let maxX = superView.frame.size.width - subView.frame.size.width/2
centerPosition.x = centerPosition.x < minX ? minX : centerPosition.x
centerPosition.x = centerPosition.x > maxX ? maxX : centerPosition.x
if !isSwiping{
let normalPosition = superView.frame.size.width * 0.5
centerPosition.x = centerPosition.x > normalPosition ? maxX : minX
centerPosition.x = centerPosition.x <= normalPosition ? minX : centerPosition.x
}
return centerPosition
}
return CGPoint.zero
}
Complete project is on github: https://github.com/IamSaurav/SwipeButton
Mmm what about something like this?
You can add an UIImage in the storyboard in the swipeImage var.
The best effect is done if the image has the same color of the text.
import UIKit
#IBDesignable
class UISwipeableLabel: UILabel {
#IBInspectable var swipeImage: UIImage? {
didSet {
configureSwipeImage()
}
}
private var swipeImageView: UIImageView?
private var rightSwipe: UIPanGestureRecognizer?
private var shouldActivateButton = true
override func awakeFromNib() {
super.awakeFromNib()
configureSwipeImage()
clipsToBounds = true
}
}
private extension UISwipeableLabel {
#objc func handleSwipes(_ sender:UIPanGestureRecognizer) {
if let centerX = swipeImageView?.center.x {
let translation = sender.translation(in: self)
let percent = centerX/frame.width
if sender.state == .changed {
if centerX < frame.width - frame.height/2 {
swipeImageView?.center.x = centerX + translation.x
sender.setTranslation(CGPoint.zero, in: swipeImageView)
} else {
swipeImageView?.center.x = frame.width - frame.height/2
if shouldActivateButton {
activateButton()
}
}
}
if sender.state == .ended || sender.state == .cancelled || sender.state == .failed {
if shouldActivateButton {
UIView.animate(withDuration: 0.25 * TimeInterval(percent)) {
self.swipeImageView?.center.x = self.frame.height/2
}
}
}
}
}
func configureSwipeImage() {
if swipeImageView != nil {
swipeImageView?.removeFromSuperview()
}
swipeImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: frame.height, height: frame.height))
if let swipeImageView = swipeImageView {
swipeImageView.image = swipeImage
swipeImageView.isUserInteractionEnabled = true
swipeImageView.alpha = 0.5
addSubview(swipeImageView)
rightSwipe = UIPanGestureRecognizer(target: self, action: #selector(handleSwipes(_:)))
if let rightSwipe = rightSwipe {
swipeImageView.addGestureRecognizer(rightSwipe)
}
}
}
func activateButton() {
print("*** DO YOUR STUFF HERE ***")
}
}
You start with a UILabel and if you want, change it to use autolayout.

How to autoscroll the scrollView horizontally?

I am using this code to scroll the scrollview horizontally when sliding the scrollview.
func getScrollView() {
upperScroll.delegate = self
upperScroll.isPagingEnabled = true
// pageControll.numberOfPages = logoImage.count
upperScroll.isScrollEnabled = true
let scrollWidth: Int = Int(self.view.frame.width)
upperScroll.contentSize = CGSize(width: CGFloat(scrollWidth), height:(self.upperScroll.frame.height))
print(upperScroll.frame.size.width)
upperScroll.backgroundColor = UIColor.clear
for index in 0..<logoImage.count {
let xPosition = self.view.frame.width * CGFloat(index)
upperScroll.layoutIfNeeded()
let img = UIImageView(frame: CGRect(x: CGFloat(xPosition), y: 0, width: upperScroll.frame.size.width, height: self.upperScroll.frame.height))
img.layoutIfNeeded()
let str = logoImage[index]
let url = URL(string: str)
img.sd_setImage(with: url, placeholderImage: UIImage(named:"vbo_logo2.png"))
upperScroll.addSubview(img)
}
view.addSubview(upperScroll)
upperScroll.contentSize = CGSize(width: CGFloat((scrollWidth) * logoImage.count), height: self.upperScroll.frame.height)
}
But i want to auto scroll?
How can i do this. Can anyone help me please.
I got the solution
#objc func animateScrollView() {
let scrollWidth = upperScroll.bounds.width
let currentXOffset = upperScroll.contentOffset.x
let lastXPos = currentXOffset + scrollWidth
if lastXPos != upperScroll.contentSize.width {
print("Scroll")
upperScroll.setContentOffset(CGPoint(x: lastXPos, y: 0), animated: true)
}
else {
print("Scroll to start")
upperScroll.setContentOffset(CGPoint(x: 0, y: 0), animated: true)
}
}
func scheduledTimerWithTimeInterval(){
// Scheduling timer to Call the function "updateCounting" with the interval of 1 seconds
timer = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(self.animateScrollView), userInfo: nil, repeats: true)
}
and call this function in ViewDidAppear
https://developer.apple.com/documentation/uikit/uiscrollview/1619400-setcontentoffset?language=objc
func scrollToPoint(point: CGPoint) {
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(10.0)) {
upperScroll.setContentOffset(point/* where you want to scroll to*/, animated:true)
}
}
you can specify the x axis when you are creating the point to pass to the func:
CGPoint(x: 100, y: 0)
There are method available to scroll for visible rect in scrollView. You need to pass CGRect in method, this means area where you want to scroll.
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated;
How about that:
let timer = Timer.scheduledTimer(timeInterval: 2, target: self, selector: (#selector(ViewController.timerAction)), userInfo: nil, repeats: true)
#objc func timerAction() {
var xOffSet = 0
xOffSet += 10
UIView.animateWithDuration(1, delay: 0, options: UIViewAnimationOptions.CurveLinear, animations: {
self.scrollView.contentOffset.x = xOffSet
}, completion: nil)
}
How to implement auto scroll in UIScrollview using Swift 3?

Custom UISlider doesn't go to end

I have created a UISlider that has tick marks and snaps to each tick when the value is changed. The problem is that the slider doesn't naturally go to the ends and the left and right tick are visible outside of the circle. I have extended the UISlider class to go to the ends but the animation conflicts with moving the slider to the next tick and the circle ends up off the screen. How can I keep the snap to tick animation and have the circle in the slider go all the way to the end? Here is my code
class CustomSlider: UISlider {
override func thumbRect(forBounds bounds: CGRect, trackRect rect: CGRect, value: Float) -> CGRect
{
let unadjustedThumbrect = super.thumbRect(forBounds: bounds, trackRect: rect, value: value)
let thumbOffsetToApplyOnEachSide:CGFloat = unadjustedThumbrect.size.width / 2.0
let minOffsetToAdd = -thumbOffsetToApplyOnEachSide
let maxOffsetToAdd = thumbOffsetToApplyOnEachSide
let offsetForValue = minOffsetToAdd + (maxOffsetToAdd - minOffsetToAdd) * CGFloat(value / (self.maximumValue - self.minimumValue))
var origin = unadjustedThumbrect.origin
origin.x += offsetForValue
return CGRect(origin: origin, size: unadjustedThumbrect.size)
}
}
#IBOutlet weak var slider: CustomSlider!
let tickArray : [Float] = [Float(18),Float(20),Float(22),Float(24),Float(26),Float(28),Float(30)]
override func viewDidLoad() {
super.viewDidLoad()
self.slider.value = tickArray[0]
self.slider.minimumValue = tickArray[0]
self.slider.maximumValue = tickArray[6]
self.slider.isContinuous = false
var tick : UIView
for i in 0..<tickArray.count-1 {
tick = UIView(frame: CGRect(x: (self.slider.frame.size.width/6) * CGFloat(i), y: (slider.frame.size.height - 13) / 2, width: 2, height: 13))
tick.backgroundColor = "8E8E93".hexColor
slider.insertSubview(tick, belowSubview: slider)
}
tick = UIView(frame: CGRect(x: self.slider.frame.size.width-2, y: (slider.frame.size.height - 13) / 2, width: 2, height: 13))
tick.backgroundColor = "8E8E93".hexColor
slider.insertSubview(tick, belowSubview: slider)
}
#IBAction func sliderValueChanged(_ sender: UISlider) {
if sender.value > tickArray[5] {
slider.value = tickArray[6]
} else if sender.value > tickArray[4] {
slider.value = tickArray[5]
} else if sender.value > tickArray[3] {
slider.value = tickArray[4]
} else if sender.value > tickArray[2] {
slider.value = tickArray[3]
} else if sender.value > tickArray[1] {
slider.value = tickArray[2]
} else if sender.value >
tickArray[0] {
slider.value = tickArray[1]
} else {
slider.value = tickArray[0]
}
}
I fixed my problem by hiding the left and right ticks when the slider goes to the edges. This took away the need for the slider extension.

UIImageView is moving back after new UIView is created

Hi I am trying to make a game using swift but am currently very stuck. My game has two buttons that move a UIImageView left and right which works perfectly although when my NSTimer calls to my animateBalls function every 2.5 seconds the UIImageView that was moved goes back to its original position. How would I be able to still be able to create a New UIView every 2.5 seconds but keep the UIIMageViews current position? Thanks for any help that you can give me, Here is my code:
import UIKit
class ViewController: UIViewController {
let speed = 10.0
#IBOutlet weak var mainBar: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
_ = NSTimer.scheduledTimerWithTimeInterval(2.5, target: self, selector: Selector("animateBalls"), userInfo: nil, repeats: true)
}
#IBAction func moveRightIsTapped(sender: AnyObject) {
if(mainBar.frame.origin.x < -158.5)
{
let xPosition = mainBar.frame.origin.x + 38.5
let yPosition = mainBar.frame.origin.y
let height = mainBar.frame.height
let width = mainBar.frame.width
mainBar.frame = CGRectMake(xPosition, yPosition, width, height)
}
}
#IBAction func moveLeftIsTapped(sender: AnyObject) {
if(mainBar.frame.origin.x > -389.5)
{
let xPosition = mainBar.frame.origin.x - 38.5
let yPosition = mainBar.frame.origin.y
let height = mainBar.frame.height
let width = mainBar.frame.width
mainBar.frame = CGRectMake(xPosition, yPosition, width, height)
}
}
#IBAction func playButtonTapped(sender: AnyObject) {
animateBalls()
}
func animateBalls() {
randomNum = Int(arc4random_uniform(1))
if(randomNum == 0)
{
let ball1 = UIView()
ball1.frame = CGRect(x: 121, y: -20, width: 20, height: 20)
ball1.layer.cornerRadius = 10
ball1.clipsToBounds = true
ball1.backgroundColor = UIColor.purpleColor()
self.view.addSubview(ball1)
UIView.animateWithDuration(speed, animations:{ ball1.frame = CGRect(x: 121, y: 705, width: ball1.frame.width, height: ball1.frame.height) })
}
if(randomNum == 1)
{
let ball2 = UIView()
ball2.frame = CGRect(x: 159, y: -20, width: 20, height: 20)
ball2.layer.cornerRadius = 10
ball2.clipsToBounds = true
ball2.backgroundColor = UIColor.greenColor()
self.view.addSubview(ball2)
UIView.animateWithDuration(speed, animations:{ ball2.frame = CGRect(x: 159, y: 705, width: ball2.frame.width, height: ball2.frame.height) })
}

Resources