Как использовать Вращение и Перевод для Изображения одновременно в iPhone? - PullRequest
0 голосов
/ 14 июля 2011

Я использовал CGAffineTransformMakeRotation для поворота изображения и CGAffineTransformMakeTranslation для трансляции изображения. Это мой код:

-(void)rotateTranslate
{
    r++;
    CGAffineTransform transform = CGAffineTransformMakeRotation(r);
    imageView.transform = transform;
    x++;
    y++;
    CGAffineTransform transform1=CGAffineTransformMakeTranslation(x,y);
    imageView.transform= transform1;
    [self performSelector:@selector(rotateTranslate) withObject:self afterDelay:0.2];
}

Моя проблема в том, что изображение только переводится, но не вращается. Если я использую Rotate и Translate отдельно, значит, это работает довольно хорошо. Как я могу изменить свой код, чтобы он работал хорошо?

Ответы [ 2 ]

3 голосов
/ 14 июля 2011

Проблема в том, что вы делаете индивидуальный поворот, а затем переводите и настраиваете его. Таким образом, вращение отменяется переводом. Вы должны сделать что-то вроде этого,

CGAffineTransform transform = CGAffineTransformRotate(imageView.transform, 1);
transform = CGAffineTransformTranslate(transform, 1, 1);

imageView.transform= transform;

[self performSelector:@selector(rotateTranslate) withObject:self afterDelay:0.2];

Но это не оживит вращение. Он просто перейдет с текущего преобразования на конечное преобразование.

А у вас, похоже, не определена конечная точка.

0 голосов
/ 31 августа 2017

Вот мой код, у меня не было времени отфильтровать код, но он включает в себя все функции, такие как поворот, перевод и масштабирование изображения в scrollview.

import UIKit

import AudioToolbox import PureLayout

let MIN_ZOOM_SCALE: CGFloat = 1 let MAX_ZOOM_SCALE: CGFloat = 5 let DEFAULT_ZOOM_SCALE: CGFloat = 2

let markerSize: CGFloat = GET_PROPORTIONAL_ont 100B: 1009UIViewController, UIScrollViewDelegate, AGConfiguratorDelegate, UITableViewDataSource, UITableViewDelegate {

@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var imageView: UIImageView!

@IBOutlet weak var btnTest: UIButton!
@IBOutlet weak var btnTest1: UIButton!
@IBOutlet weak var btnTest2: UIButton!


var markerCount:Int = 0
var arrPlacedMarkers = [UIButton]()
var isPullViewOpened:Bool = false
var table:UITableView!
var viewHeader:UIView!

var viewBtnContainer:UIView!

var timerRotateButtons:Timer!

var btnRotateLeft:UIButton!
var btnRotateRight:UIButton!
var selectedBtnMarker:UIButton?

var maxYTouchPointToScrollUp:CGFloat = -1

let configurator = AGPullViewConfigurator()

//MARK:- VIEW
override func viewDidLoad() {
    super.viewDidLoad()

    self.doSetupUI()

    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2) {

// var xx = SCREEN_WIDTH * 257.076682316119 / self.imageView.image!.image! .size.height

// var xx = SCREEN_WIDTH * 395.150738305702 / self.imageView.image! .size.width // var yy = SCREEN_HEIGHT * 295.700957624736 / self.imageView.image! .size.высота

        var xx = SCREEN_WIDTH * 253.0 / self.imageView.image!.size.width
        var yy = SCREEN_HEIGHT * 591.549295774648 / self.imageView.image!.size.height


        print("xx : \(xx) yy : \(yy) ")
        xx = xx + (markerSize/2)
        yy = yy + (markerSize/2)
        print("xx : \(xx) yy : \(yy) ")

        self.addButtonWithAtPoint(touchedPoint: CGPoint(x: xx, y: yy))

        print("\nMAP : \(self.imageView.image!.size)")
        print("SCR : \(self.scrollView.frame)")
        print("VIE : \(self.view.frame)")
    }
}

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
}

//For correct working of layout in early versions of iOS 10
override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    self.configurator.layoutPullView()

    let pullViewHeight = self.configurator.contentView.superview?.frame.size.height

    self.maxYTouchPointToScrollUp = (SCREEN_HEIGHT - (pullViewHeight)! - scrollView.frame.origin.y)
}

//MARK:- SAVE MARKER IN DEFAULTS

func saveMarkerInDefault(){

    var counter:Int = 0

    for eachButton in arrPlacedMarkers{

        print(" \(counter) x : \(eachButton.frame.origin.x) y : \(eachButton.frame.origin.y)")
        if(counter == 0){

            let xPos = eachButton.frame.origin.x
            let yPos = eachButton.frame.origin.y

            let newXPos = (imageView.image!.size.width * xPos) / SCREEN_WIDTH
            let newYPos = (imageView.image!.size.height * yPos) / SCREEN_HEIGHT

            print("default stored   x : \(newXPos) y : \(newYPos)")

            UserDefaults.standard.set(newXPos, forKey: "xPos")
            UserDefaults.standard.set(newYPos, forKey: "yPos")
        }

        counter += 1
    }
}

func getMarkerFromDefaults() -> [AIMarker]{

    var arrSavedMarker = [AIMarker]()

    if let xPos = UserDefaults.standard.object(forKey: "xPos") as? CGFloat{
        if let yPos = UserDefaults.standard.object(forKey: "yPos") as? CGFloat{
            let marker = AIMarker(x: xPos, y: yPos)
            arrSavedMarker.append(marker)
        }
    }

    return arrSavedMarker
}


//MARK:- UI SETUP
func doSetupUI() {


    btnTest.isHidden = true
    btnTest1.isHidden = true
    btnTest2.isHidden = true


    // IMAGEVIEW
    imageView.clipsToBounds = true
    imageView.contentMode = UIViewContentMode.scaleToFill
    imageView.isUserInteractionEnabled = true
    imageView.image = UIImage(named: "RoomPlan2")

    self.scrollView.applyBorderDefault()


    // SCROLLVIEW
    scrollView.minimumZoomScale = MIN_ZOOM_SCALE
    scrollView.maximumZoomScale = MAX_ZOOM_SCALE
    scrollView.zoomScale = DEFAULT_ZOOM_SCALE

    scrollView.delegate = self
    scrollView.bounces = false
    scrollView.bouncesZoom = false


    // SINGLE TAP
    let singleTap = UITapGestureRecognizer(target: self, action: #selector(self.singleTapHandler(_ :)))
    singleTap.numberOfTapsRequired = 1
    singleTap.numberOfTouchesRequired = 1
    imageView.addGestureRecognizer(singleTap)


    // DOUBLE TAP
    let doubleTap = UITapGestureRecognizer(target: self, action: #selector(self.doubleTapHandler(_ :)))
    doubleTap.numberOfTapsRequired = 2
    doubleTap.numberOfTouchesRequired = 1
    imageView.addGestureRecognizer(doubleTap)
    singleTap.require(toFail: doubleTap)


    // LONG PRESS
    let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(self.longPressHandlerForMapImageView(_:)))
    imageView.addGestureRecognizer(longPressGesture)


    self.doSetupRotateButtons()

    self.doSetupPullView()



}

func doSetupRotateButtons(){


    let btnSize:CGFloat = GET_PROPORTIONAL_HEIGHT(height: 30)
    let viewBtnContainerTrailingSpace:CGFloat = GET_PROPORTIONAL_HEIGHT(height: 10)
    let spaceBetweenBtns:CGFloat = GET_PROPORTIONAL_HEIGHT(height: 10)


    // VIEW BTN CONTAINER
    viewBtnContainer = UIView(forAutoLayout: ())
    self.view.addSubview(viewBtnContainer)
    viewBtnContainer.autoPinEdge(toSuperviewEdge: ALEdge.trailing, withInset: GET_PROPORTIONAL_HEIGHT(height: viewBtnContainerTrailingSpace))

    // BTN ROTATE LEFT
    btnRotateLeft = UIButton(type: .system)
    viewBtnContainer.addSubview(btnRotateLeft)
    btnRotateLeft.addTarget(self, action: #selector(self.btnRotateLeftHandler(sender:)), for: .touchUpInside)
    btnRotateLeft.isExclusiveTouch = true
    btnRotateLeft.setImage(UIImage(named: "rotate_left"), for: .normal)
    btnRotateLeft.imageView?.contentMode = UIViewContentMode.scaleAspectFit

    btnRotateLeft.autoSetDimensions(to: CGSize(width: btnSize, height: btnSize))
    btnRotateLeft.autoPinEdgesToSuperviewEdges(with: UIEdgeInsetsMake(5, 5, 5, 5), excludingEdge: ALEdge.trailing)



    // BTN ROTATE RIGHT
    btnRotateRight = UIButton(type: .system)
    viewBtnContainer.addSubview(btnRotateRight)
    btnRotateRight.addTarget(self, action: #selector(self.btnRotateRightHandler(sender:)), for: .touchUpInside)
    btnRotateRight.isExclusiveTouch = true
    btnRotateRight.setImage(UIImage(named: "rotate_right"), for: .normal)
    btnRotateRight.imageView?.contentMode = UIViewContentMode.scaleAspectFit

    btnRotateRight.autoSetDimensions(to: CGSize(width: btnSize, height: btnSize))
    btnRotateRight.autoPinEdgesToSuperviewEdges(with: UIEdgeInsetsMake(5, 5, 5, 5), excludingEdge: ALEdge.leading)
    btnRotateRight.autoPinEdge(ALEdge.leading, to: ALEdge.trailing, of: btnRotateLeft, withOffset: spaceBetweenBtns)



    btnRotateLeft.tag = 111
    btnRotateRight.tag = 222

    // ADDING LONG PRESS GESTURE
    let longPressGestureRotateLeft = UILongPressGestureRecognizer(target: self, action: #selector(self.longPressHandlerForRotateLeftButton(_:)))
    btnRotateLeft.addGestureRecognizer(longPressGestureRotateLeft)

    let longPressGestureRotateRight = UILongPressGestureRecognizer(target: self, action: #selector(self.longPressHandlerForRotateRightButton(_:)))
    btnRotateRight.addGestureRecognizer(longPressGestureRotateRight)

// viewBtnContainer.applyBorder (цвет: UIColor.red, ширина: 2) // btnRotateRight.applyBorderDefault () // btnRotateLeft.applyBorderDefault ()

}

//MARK:- *********
func doSetupPullView(){

    self.configurator.setupPullView(forSuperview: self.view, colorScheme: ColorSchemeTypeWhite)

// let pullViewHeight = self.configurator.contentView.superview? .frame.size.height // print ("PULL VIEW HEIGHT: ((self.configurator.contentView.superview? .frame)!) ") // print (" IMG: (imageView.frame) SC: (scrollView.frame) ") // print (" ВЫСОТА ЭКРАНА: (SCREEN_HEIGHT) XX: (SCREEN_HEIGHT- pullViewHeight!- scrollView.frame.origin.y) ") // let maxBottomTapValue = (SCREEN_HEIGHT - pullViewHeight! - scrollView.frame.origin.y)

    viewBtnContainer.autoPinEdge(toSuperviewEdge: ALEdge.bottom, withInset: (height: self.configurator.contentView.superview!.frame.size.height))

    self.configurator.percentOfFilling = 90//85
    self.configurator.delegate = self
    self.configurator.needBounceEffect = true
    self.configurator.animationDuration = 0.45
    self.configurator.enableShowingWithTouch = true;
    self.configurator.enableHidingWithTouch = true;
    self.configurator.enableBlurEffect(withBlurStyle: .dark)


    self.hidePullViewFromBottom(animated: false)

    //Test UITableView
    table = UITableView(frame: CGRect(), style: .plain)
    table.dataSource = self
    table.delegate = self
    table.separatorStyle = .none;
    table.backgroundColor = UIColor.clear
    table.isUserInteractionEnabled = false



    let viewFooter = UIView(frame: CGRect(x: 0, y: 0, width: SCREEN_WIDTH, height: GET_PROPORTIONAL_HEIGHT(height: 40)))
    viewFooter.backgroundColor = UIColor.lightGray
    let btnRemoveMarker = UIButton(forAutoLayout: ())
    btnRemoveMarker.setTitle("Remove Marker", for: .normal)
    btnRemoveMarker.addTarget(self, action: #selector(self.btnRemoveMarkerTapHandler(_:)), for: .touchUpInside)
    viewFooter.addSubview(btnRemoveMarker)
    btnRemoveMarker.autoCenterInSuperview()

    table.tableFooterView = viewFooter


    //Filling whole AGPullView with test UITableView
    self.configurator.fullfillContentView(with: table)

    self.configurator.blockBtnCloseHandler = {
        if(self.isPullViewOpened){
            self.configurator.hide(animated: true)
        }else{
            self.hidePullViewFromBottom(animated: true)
        }
    }
}

//MARK:- *********

//MARK:- SHOW / HIDE PULL VIEW

func showPullViewAtBottom(animated isAnimated:Bool){

    let tempSuperView = self.configurator.contentView.superview
    if(tempSuperView!.transform.isIdentity && tempSuperView?.isHidden == false){

// print (" уже открыт ") return}tempSuperView? .isHidden = false self.configurator.doShowTopBottomButtons () tempSuperView? .transform = CGAffineTransform.init (translationX: 0, y: tempSuperView! .height) UIView.animate (withDuration: 0.2, animations: {tempSuformform CGA)..init (translationX: 0, y: 0)}) {(bbb) in}

    showRotateButtons(withAnimation: isAnimated)
}

func hidePullViewFromBottom(animated isAnimated:Bool){

    let tempSuperView = self.configurator.contentView.superview

    if(tempSuperView!.transform.isIdentity && tempSuperView?.isHidden == true){

// print ("уже закрыто") return}

    let duration:TimeInterval = isAnimated ? 0.2 : 0.0

    UIView.animate(withDuration: duration, animations: {
        tempSuperView?.transform = CGAffineTransform.init(translationX: 0, y: tempSuperView!.height)
    }) { (bbb) in
        tempSuperView?.transform = CGAffineTransform.init(translationX: 0, y: 0)
        tempSuperView?.isHidden = true
        self.configurator.doHideTopBottomButtons()
    }

    hideRotateButtons(withAnimation: isAnimated)

}

//MARK:- SHOW / HIDE ROTATE BUTTONS
func showRotateButtons(withAnimation animated:Bool){

    if self.viewBtnContainer != nil{
        UIView.animate(withDuration: animated ? 0.2 : 0.0, animations: {
            self.viewBtnContainer.alpha = 1
        }) { (bb) in
        }
    }

}

func hideRotateButtons(withAnimation animated:Bool){

    if self.viewBtnContainer != nil{
        UIView.animate(withDuration: animated ? 0.1 : 0.0, animations: {
            self.viewBtnContainer.alpha = 0
        }) { (bb) in
        }
    }

}


//MARK:- ADD BUTTON

func addButtonWithAtPoint(touchedPoint:CGPoint) {

    print("\n\n\nTOUCH POINT : \(touchedPoint)")


    // CREATING BUTTON FOR MARKER
    let xPos = touchedPoint.x - (markerSize/2)
    let yPos = touchedPoint.y - (markerSize/2)





    let btnMarker = UIButton(type: .custom)
    btnMarker.frame = CGRect(x: xPos, y: yPos, width: markerSize, height: markerSize)

    print("xpos : \(xPos) ypos : \(yPos)----\(btnMarker.frame)")
    print("ce----\(btnMarker.center)")

    btnMarker.setTitleColor(UIColor.white, for: .normal)
    btnMarker.setTitle("M\(markerCount + 1)", for: .normal)
    btnMarker.tag = markerCount
    btnMarker.titleLabel?.numberOfLines = 1
    btnMarker.titleLabel?.adjustsFontSizeToFitWidth = true
    btnMarker.titleLabel?.lineBreakMode = .byClipping
    btnMarker.addTarget(self, action: #selector(self.btnMarkerTapHandler(_:)), for: .touchUpInside)
    self.imageView.addSubview(btnMarker)

    let imageArrow = UIImage(named: "arrow")
    btnMarker.setImage(imageArrow, for: .normal)


    // ADDING PAN GESTURE
    let panGesture = UIPanGestureRecognizer(target: self, action: #selector(self.panGestureHandler(_:)))
    btnMarker.addGestureRecognizer(panGesture)


    // ADDING ROTATION GESTURE

//let rotateGesture = UIRotationGestureRecognizer (target: self, action: #selector (self.rotationGestureHandler (_ :))) // btnMarker.addGestureRecognizer (rotateGesture)

    // ADDING MARKER IN MAIN ARRAY
    self.arrPlacedMarkers.append(btnMarker)
    markerCount += 1


    // SCALING MARKER AS PER MAP'S CURRENT ZOOM SCALE
    let invertedTransform = CGAffineTransform.inverted(imageView.transform)
    for eachSubview in imageView.subviews{
        let angle = atan2f(Float(eachSubview.transform.b), Float(eachSubview.transform.a));
        eachSubview.transform = invertedTransform().rotated(by: CGFloat(angle))
    }


    playVibrate()

    presentPullViewForMarker(btnMarker: btnMarker)

// btnMarker.applyBorderef*

func playVibrate(){

// AudioServicesPlaySystemSound (kSystemSoundID_Vibrate);}

func presentPullViewForMarker(btnMarker:UIButton){

    self.selectedBtnMarker = btnMarker

    self.showPullViewAtBottom(animated: true)
    (viewHeader.subviews.first as! UIButton).setTitle("Add Photos for : \((btnMarker.titleLabel?.text)!)", for: .normal)
}


//MARK:- BUTTON EVENTS

func btnMarkerTapHandler(_ sender:UIButton){
    self.presentPullViewForMarker(btnMarker: sender)
}

func btnAddPhotosTapHandler(_ sender:UIButton){

    saveMarkerInDefault()

// let secondVC = self.storyboard? .InstantiateViewController (withIdentifier: "SecondViewController") как! SecondViewController //self.navigationController? .pushViewController (secondVC, animated: true) // self.present (secondVC, animated: true) {//
//}}

func btnRemoveMarkerTapHandler(_ sender:UIButton){



    if let selectedBtnMarker = self.selectedBtnMarker {

        showAlertWithTitle(title: "Remove Marker \((selectedBtnMarker.titleLabel?.text)!)", message: "Are you sure you want to remove this marker ?", buttons: ["Cancel","Yes"], showsCancelOption: false, completion: { (selectedIndex) in
            if(selectedIndex == 1){
                if let validIndex = self.arrPlacedMarkers.index(of: selectedBtnMarker){
                    self.arrPlacedMarkers.remove(at: validIndex)
                    self.selectedBtnMarker?.removeFromSuperview()


                    DispatchQueue.main.async {
                        self.configurator.hide(animated: true)

                        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.4) {
                            self.hidePullViewFromBottom(animated: true)
                        }
                    }


                }
            }
        })
    }
}

//MARK:-
func btnRotateLeftHandler(sender:UIButton){
    if let selectedBtnMarker = self.selectedBtnMarker {
        selectedBtnMarker.rotate(angle: -5)
    }
}
func btnRotateRightHandler(sender:UIButton){
    if let selectedBtnMarker = self.selectedBtnMarker {
        selectedBtnMarker.rotate(angle: 5)
    }
}




//MARK:-

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 10
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = UITableViewCell()
    cell.backgroundColor = UIColor.clear
    cell.textLabel?.textColor = UIColor.gray
    cell.textLabel?.text = "Photo \(indexPath.row + 1)"
    return cell;
}

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {

    viewHeader = UIView(frame: CGRect(x: 0, y: 0, width: SCREEN_WIDTH, height: 100))
    viewHeader.backgroundColor = UIColor.lightGray
    let btnAddPhotos = UIButton(forAutoLayout: ())
    btnAddPhotos.setTitle("Add Photos", for: .normal)
    btnAddPhotos.addTarget(self, action: #selector(self.btnAddPhotosTapHandler(_:)), for: .touchUpInside)
    viewHeader.addSubview(btnAddPhotos)
    btnAddPhotos.autoCenterInSuperview()

    return viewHeader
}

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return GET_PROPORTIONAL_HEIGHT(height: 40)
}


//MARK:-
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    self.configurator.handleTouchesBegan(touches)
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    self.configurator.handleTouchesMoved(touches)
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    self.configurator.handleTouchesEnded(touches)
}


//MARK:- AGPullView DELEGATES
func didDrag(_ pullView: AGPullView!, withOpeningPercent openingPercent: Float) {

// print ("didперетаскивать: (OpeningPercent) ") открытиеПерцент> 0,0?hideRotateButtons (withAnimation: true): showRotateButtons (withAnimation: true)}

func didShow(_ pullView: AGPullView!) {
    print("shown");
    isPullViewOpened = true
    table.isUserInteractionEnabled = true

    hideRotateButtons(withAnimation: true)
}

func didHide(_ pullView: AGPullView!) {
    print("hidden")
    isPullViewOpened = false
    table.isUserInteractionEnabled = false

    showRotateButtons(withAnimation: true)
}

func didTouch(toShow pullView: AGPullView!) {
    print("touched to show")
}

func didTouch(toHide pullView: AGPullView!) {
    print("touched to hide")
}

//MARK:- PAN GESTURE HANDLER

func panGestureHandler(_ recognizer:UIPanGestureRecognizer){

    if(recognizer.state == .changed || recognizer.state == .ended) {
        let draggedButton = recognizer.view

        var newFrame = draggedButton?.frame
        if(newFrame!.origin.x < 0.0){
            newFrame!.origin.x = 0.0
        }
        if(newFrame!.origin.y < 0.0){
            newFrame!.origin.y = 0.0
        }

        let oldXPlusWidth = newFrame!.origin.x + newFrame!.size.width
        let trailingMarginToKeep = self.imageView.bounds.size.width - newFrame!.size.width
        if(oldXPlusWidth > self.imageView.bounds.size.width){
            newFrame!.origin.x = trailingMarginToKeep
        }

        let oldYPlusHeight = newFrame!.origin.y + newFrame!.size.height
        let bottomMarginToKeep = self.imageView.bounds.size.height - newFrame!.size.height
        if(oldYPlusHeight > self.imageView.bounds.size.height){
            newFrame!.origin.y = bottomMarginToKeep
        }

        let translationPoint = recognizer.translation(in: self.imageView)

        newFrame?.origin.x += translationPoint.x
        newFrame?.origin.y += translationPoint.y

        let centerX:CGFloat = newFrame!.origin.x + (newFrame!.size.width/2)
        let centerY:CGFloat = newFrame!.origin.y + (newFrame!.size.height/2)

        draggedButton?.center = CGPoint(x: centerX, y: centerY)

        recognizer.setTranslation(CGPoint.zero, in: self.imageView)
    }
}


//MARK:- ROTATION GESTURE HANDLER
func rotationGestureHandler(_ recognizer:UIRotationGestureRecognizer){
    recognizer.view!.transform = recognizer.view!.transform.rotated(by: recognizer.rotation)
    recognizer.rotation = 0
}

//MARK:- LONG PRESS HANDLER
func longPressHandlerForMapImageView(_ sender:UILongPressGestureRecognizer){

    if sender.state == .began{

// self.addButtonWithAtPoint (touchedPoint: sender.location (in: sender.view)) self.addButtonWithAtPoint (touchedPoint: sender).location (in: imageView))}}

func longPressHandlerForRotateLeftButton(_ sender:UILongPressGestureRecognizer){

    switch sender.state {
    case .began:
        self.timerRotateButtons = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(self.timerHandlerForRotateButton(sender:)), userInfo: sender.view, repeats: true)
    case .ended:
        self.timerRotateButtons.invalidate()
        self.timerRotateButtons = nil
    default:
        break
    }
}

func longPressHandlerForRotateRightButton(_ sender:UILongPressGestureRecognizer){

    switch sender.state {
    case .began:
        self.timerRotateButtons = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(self.timerHandlerForRotateButton(sender:)), userInfo: sender.view, repeats: true)
    case .ended:
        self.timerRotateButtons.invalidate()
        self.timerRotateButtons = nil
    default:
        break
    }
}

//MARK:- TIMER 
func timerHandlerForRotateButton(sender:Timer){

    if let btn:UIButton = sender.userInfo as? UIButton{
        var rotateAngle:CGFloat = 0
        if(btn == btnRotateLeft){
            rotateAngle = -1
        }else if(btn == btnRotateRight){
            rotateAngle = 1
        }
        if let selectedBtnMarker = self.selectedBtnMarker {
            selectedBtnMarker.rotate(angle: rotateAngle)
        }
    }
}



//MARK:- TAP GESTURE HANDLER
func singleTapHandler(_ sender:UITapGestureRecognizer){

// print («ОДИН КАРТЫ»)

    if(self.isPullViewOpened){

// print («ОДИН КАРТЫ: не закрывать ..открытое ")} else {self.hidePullViewFromBottom (animated: true)}

}

func doubleTapHandler(_ sender:UITapGestureRecognizer){

// print (" DOUBLE TAP (scrollView.minimumZoomScale) (scrollView.maximumZoomScale) (scrollView.zoomScale) ")

    // ZOOM RESET
    if(scrollView.zoomScale > scrollView.minimumZoomScale){
        scrollView.setZoomScale(scrollView.minimumZoomScale, animated: true)
    }else{
        // ZOOM IN
        let zoomRect = self.zoomRectForScale(scale: DEFAULT_ZOOM_SCALE, withCenter: sender.location(in: sender.view))
        scrollView.zoom(to: zoomRect, animated: true)
    }
}


func zoomRectForScale(scale:CGFloat, withCenter center:CGPoint) -> CGRect {

    var zooomRect:CGRect = CGRect()
    zooomRect.size.height = imageView.frame.size.height / scale
    zooomRect.size.width = imageView.frame.size.width / scale

    let tempCenter = imageView.convert(center, from: self.imageView)
    zooomRect.origin.x = tempCenter.x - (zooomRect.size.width / 2.0)
    zooomRect.origin.y = tempCenter.y - (zooomRect.size.height / 2.0)
    return zooomRect
}


//MARK:- BUTTION EVENTS
@IBAction func btnTestPressed(_ sender: Any) {
    //      print("BTN 10 % TAP")


    showAlertWithTitle(title: "title", message: "message", buttons: ["b1","b2"], showsCancelOption: false) { (selecgtedIndex) in
        print("selected \(selecgtedIndex)")
    }
}

@IBAction func btnTest1Pressed(_ sender: Any) {
    //      print("\n\nBTN 90 % TAP")
}

@IBAction func btnTest2Pressed(_ sender: Any) {
    //      print("BTN RESET TAP")
    scrollView.setZoomScale(1, animated: true)
}



//MARK:- SCROLLVIEW DELEGATE

func viewForZooming(in scrollView: UIScrollView) -> UIView? {
    return imageView
}


func scrollViewDidScroll(_ scrollView: UIScrollView) {

// print ("\ n \ n (#function) (scrollView.zoomScale) __ (scrollView.contentSize) __ (scrollView.contentOffset) \ n")

    let invertedTransform = CGAffineTransform.inverted(imageView.transform)
    for eachSubview in imageView.subviews{
        let angle = atan2f(Float(eachSubview.transform.b), Float(eachSubview.transform.a));
        eachSubview.transform = invertedTransform().rotated(by: CGFloat(angle))
    }

    if(self.isPullViewOpened){

// print ("scroll: not close .. open")} else {self.hidePullViewFromBottom (animated: true)}}}

//MARK:-
func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool {
    print("\n\(#function)\n")
    return false
}

// func scrollViewDidScrollToTop (_ scrollView: UIScrollView) {// print ("\ n (#function) \ n") //} // //
// // MARK: -// func scrollViewDidEndScrollingAnimation (_ scrollView: UIScrollView) { // печать ("\ n (#function) \ n") //} //ОТМЕТКА:- // func scrollViewWillBeginZooming (_ scrollView: UIScrollView, с представлением: UIView?) { // печать ("\ n (#function) \ n") //} // func scrollViewDidZoom (_ scrollView: UIScrollView) { // print ("\ n (#function) (scrollView.zoomScale) __ (scrollView.contentSize) __ (scrollView.contentOffset)") //} func scrollViewDidEndZooming (_ scrollView: UIScrollView, с представлением: UIView ?, в масштабе шкалы: CGFloat) { // print ("\ n (#function) \ n")

    let invertedTransform = CGAffineTransform.inverted(imageView.transform)
    for eachSubview in imageView.subviews{
        let angle = atan2f(Float(eachSubview.transform.b), Float(eachSubview.transform.a));
        eachSubview.transform = invertedTransform().rotated(by: CGFloat(angle))
    }

// для i в 0 ..

// для i в 0 ..

}


//MARK:-

// func scrollViewWillBeginDragging (_ scrollView: UIScrollView) { // печать ("\ n (#function) \ n") //} // func scrollViewWillEndDragging (_ scrollView: UIScrollView, withVelocity speed: CGPoint, targetContentOffset: UnsafeMutablePointer) { // печать ("\ n (#function) \ n") //} // func scrollViewDidEndDragging (_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { // печать ("\ n (#function) \ n") //} // func scrollViewWillBeginDecelerating (_ scrollView: UIScrollView) { // печать ("\ n (#function) \ n") //} // func scrollViewDidEndDecelerating (_ scrollView: UIScrollView) { // печать ("\ n (#function) \ n") //}

}

...