Переміщення UIView в межах батьківського UIView (UIPanGestureRecognizer)

Я використовую наступний код для переміщення UIImageView, який присутній всередині UIView.

- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer {

CGPoint translation = [recognizer translationInView:self.view];
recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x,
                                     recognizer.view.center.y + translation.y);
[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];

}

Я хотів би зробити так, щоб UIView не переходив за межі батьківського виду. У хвилину перегляду зображень можна переміщати по всьому екрану.

12

8 Відповіді

Спочатку отримаєте новий фрейм вашого UIImageView і перевірте, чи він повністю знаходиться всередині його superview, використовуючи метод CGRectContainsRect() . Якщо так, то встановіть рамку UImageView до нового кадру.

- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer {

    CGPoint translation = [recognizer translationInView:self.view];
    CGRect recognizerFrame = recognizer.view.frame;
    recognizerFrame.origin.x += translation.x;
    recognizerFrame.origin.y += translation.y; 

   //Check if UIImageView is completely inside its superView
    if (CGRectContainsRect(self.view.bounds, recognizerFrame)) {
        recognizer.view.frame = recognizerFrame;
    }
   //Else check if UIImageView is vertically and/or horizontally outside of its
   //superView. If yes, then set UImageView's frame accordingly.
   //This is required so that when user pans rapidly then it provides smooth translation.
    else {
       //Check vertically
        if (recognizerFrame.origin.y < self.view.bounds.origin.y) {
            recognizerFrame.origin.y = 0;
        }        
        else if (recognizerFrame.origin.y + recognizerFrame.size.height > self.view.bounds.size.height) {
            recognizerFrame.origin.y = self.view.bounds.size.height - recognizerFrame.size.height;
        }

       //Check horizantally
        if (recognizerFrame.origin.x < self.view.bounds.origin.x) {
            recognizerFrame.origin.x = 0;
        }
        else if (recognizerFrame.origin.x + recognizerFrame.size.width > self.view.bounds.size.width) {
            recognizerFrame.origin.x = self.view.bounds.size.width - recognizerFrame.size.width;
        }
    }

   //Reset translation so that on next pan recognition
   //we get correct translation value
    [recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
}

Переконайтеся, що ви передаєте bounds superview і frame UIImageView , так що обидва CGRects знаходяться в одній системі координат.

11
додано
@micantox Я згоден з деякими вашими очками і оновив мою відповідь. Для superview я знаю, що self.view є superView зображення, тому що він сам використав self.view як superview у своєму коді.
додано Автор Geek, джерело
@IconicDigital Подивіться на мою оновлену відповідь, щоб мати правильний ефект перекладу у всіх випадках.
додано Автор Geek, джерело
@RidelBelton Правильно, що вам слід використовувати recognizer.view.frame . Причина, чому воно не рухалося, може бути "ви не змінювали його значення взагалі", або "ви змінили рамку зору, відмінну від того, що ви хочете перетягнути".
додано Автор Geek, джерело
Я не впевнений, що мені не вистачає, але UIPanGestureRecognizer не має властивості "frame", звідки я сиджу ... так recognizer.frame не працює. Я міг би використовувати recognizer.view.frame, але тоді встановлення recognizer.view.frame в recognizerFrame, здавалося б, нічого не зробило, тому що я просто призначив ту саму цінність назад собі. Я спробував інший метод нижче, який добре працює для мене, але все ж цікаво на цьому. Якщо хтось може порадити, я ціную це, спасибі.
додано Автор Reid Belton, джерело
Це все гарно і добре, крім цього: ви не знаєте, що функція recognizer.view є self.view І якщо користувач швидко запускається за рамки контролю, ви отримаєте потворний ефект заморожування кадру розпізнавання посередині меж контролю. І нарешті, якщо цей користувач продовжує панорамування, вигляд зберігатиме панорамування, не перебуваючи під пальцем користувача. Взагалі, ви можете зробити краще.
додано Автор micantox, джерело

Спробуйте з:

- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer 
{
    if (gesture.state==UIGestureRecognizerStateChanged || gesture.state == UIGestureRecognizerStateEnded){
        UIView *superview = recognizer.view.superview;
        CGSize superviewSize = superview.bounds.size;
        CGSize thisSize = recognizer.view.size;
        CGPoint translation = [recognizer translationInView:self.view];
        CGPoint center = CGPointMake(recognizer.view.center.x + translation.x,
                                 recognizer.view.center.y + translation.y);

        CGPoint resetTranslation = CGPointMake(translation.x, translation.y);

        if(center.x - thisSize.width/2 < 0)
            center.x = thisSize.width/2;
        else if (center.x + thisSize.width/2 > superviewSize.width)
            center.x = superviewSize.width-thisSize.width/2;
        else
            resetTranslation.x = 0; //Only reset the horizontal translation if the view *did* translate horizontally

        if(center.y - thisSize.height/2 < 0)
            center.y = thisSize.height/2;
        else if(center.y + thisSize.height/2 > superviewSize.height)
            center.y = superviewSize.height-thisSize.height/2;
        else
            resetTranslation.y = 0; //Only reset the vertical translation if the view *did* translate vertically

        recognizer.view.center = center;
        [recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
    }
}

Таким чином, він ніколи не переміщатиметься за межі батьківського виду, і він буде просто "прилипати" до краю, якщо ви намагаєтесь перемістити його за межі!

8
додано
працює як чарівність! спасибі
додано Автор MBH, джерело

Спробуйте з:

- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer 
{
    if (gesture.state==UIGestureRecognizerStateChanged || gesture.state == UIGestureRecognizerStateEnded){
        UIView *superview = recognizer.view.superview;
        CGSize superviewSize = superview.bounds.size;
        CGSize thisSize = recognizer.view.size;
        CGPoint translation = [recognizer translationInView:self.view];
        CGPoint center = CGPointMake(recognizer.view.center.x + translation.x,
                                 recognizer.view.center.y + translation.y);

        CGPoint resetTranslation = CGPointMake(translation.x, translation.y);

        if(center.x - thisSize.width/2 < 0)
            center.x = thisSize.width/2;
        else if (center.x + thisSize.width/2 > superviewSize.width)
            center.x = superviewSize.width-thisSize.width/2;
        else
            resetTranslation.x = 0; //Only reset the horizontal translation if the view *did* translate horizontally

        if(center.y - thisSize.height/2 < 0)
            center.y = thisSize.height/2;
        else if(center.y + thisSize.height/2 > superviewSize.height)
            center.y = superviewSize.height-thisSize.height/2;
        else
            resetTranslation.y = 0; //Only reset the vertical translation if the view *did* translate vertically

        recognizer.view.center = center;
        [recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
    }
}

Таким чином, він ніколи не переміщатиметься за межі батьківського виду, і він буде просто "прилипати" до краю, якщо ви намагаєтесь перемістити його за межі!

8
додано
працює як чарівність! спасибі
додано Автор MBH, джерело

Ви повинні встановити recognizer.view.center на нове значення, тільки якщо його рамка знаходиться всередині межі його батьківського виду. Використовуйте CGRectContainsRect на recognizer.view.superview.bounds </код "і" код> recognizer.view.frame , щоб переконатися, що вони містяться.

Якщо ви хочете дозволити перегляду зображень переміщатися поза його батьківським представленням, доки центральна точка зору не знаходиться за межами батьківського коду, ви можете скористатися методом convertPoint: toView UIView і переконайтеся, що новий CGPoint не знаходиться за межі вашого батька.

1
додано

Ви повинні встановити recognizer.view.center на нове значення, тільки якщо його рамка знаходиться всередині межі його батьківського виду. Використовуйте CGRectContainsRect на recognizer.view.superview.bounds </код "і" код> recognizer.view.frame , щоб переконатися, що вони містяться.

Якщо ви хочете дозволити перегляду зображень переміщатися поза його батьківським представленням, доки центральна точка зору не знаходиться за межами батьківського коду, ви можете скористатися методом convertPoint: toView UIView і переконайтеся, що новий CGPoint не знаходиться за межі вашого батька.

1
додано

Swift версія мікатоксової відповіді

let gesture = UIPanGestureRecognizer(target: self, action: #selector(self.wasDragged(gestureRecognizer:)))
imageView.addGestureRecognizer(gesture)
imageView.isUserInteractionEnabled = true

@objc func wasDragged(gestureRecognizer: UIPanGestureRecognizer) {
if gestureRecognizer.state == UIGestureRecognizerState.changed || gestureRecognizer.state == UIGestureRecognizerState.ended {
   let superview = gestureRecognizer.view?.superview
   let superviewSize = superview?.bounds.size
   let thisSize = gestureRecognizer.view?.frame.size
   let translation = gestureRecognizer.translation(in: self.view)
   var center = CGPoint(x: gestureRecognizer.view!.center.x + translation.x, y: gestureRecognizer.view!.center.y + translation.y)
   var resetTranslation = CGPoint(x: translation.x, y: translation.y)

   if center.x - (thisSize?.width)!/2 < 0 {
       center.x = (thisSize?.width)!/2
       } else if center.x + (thisSize?.width)!/2 > (superviewSize?.width)! {
       center.x = (superviewSize?.width)!-(thisSize?.width)!/2
       } else {
         resetTranslation.x = 0 //Only reset the horizontal translation if the view *did* translate horizontally
       }

   if center.y - (thisSize?.height)!/2 < 0 {
       center.y = (thisSize?.height)!/2
      } else if center.y + (thisSize?.height)!/2 > (superviewSize?.height)! {
       center.y = (superviewSize?.height)!-(thisSize?.height)!/2
      } else {
        resetTranslation.y = 0 //Only reset the vertical translation if the view *did* translate vertically
      }

      gestureRecognizer.view?.center = center
      gestureRecognizer.setTranslation(CGPoint(x: 0, y: 0), in: self.view)
    } 
}
0
додано
if (gesture.state==UIGestureRecognizerStateChanged){

CGPoint translation = [recognizer translationInView:self.view];

CGRect rectToCheck=CGRectMake(yourView.frame.origin.x+translation.x,       yourView.frame.origin.y+translation.y, CGRectGetWidth(yourView.frame),     CGRectGetHeight(yourView.frame));

     if(CGRectContainsRect(self.view.bounds,rectToCheck))// check that the rect that is   going to form lies within the bounds of self.view
     {

     yourView.frame=CGRectMake(yourView.frame.origin.x+translation.x,  yourView.frame.origin.y+translation.y, CGRectGetWidth(yourView.frame),  CGRectGetHeight(yourView.frame)); 
     }
     [gesture setTranslation:CGPointZero yourView];//important to set this 

 }

П.С. Використовуйте блок стану жесту для ініціації, панорамування, видалення. тобто UIGestureRecognizerStateBegan UIGestureRecognizerStateChanged UIGestureRecognizerStateEnded

0
додано
if (gesture.state==UIGestureRecognizerStateChanged){

CGPoint translation = [recognizer translationInView:self.view];

CGRect rectToCheck=CGRectMake(yourView.frame.origin.x+translation.x,       yourView.frame.origin.y+translation.y, CGRectGetWidth(yourView.frame),     CGRectGetHeight(yourView.frame));

     if(CGRectContainsRect(self.view.bounds,rectToCheck))// check that the rect that is   going to form lies within the bounds of self.view
     {

     yourView.frame=CGRectMake(yourView.frame.origin.x+translation.x,  yourView.frame.origin.y+translation.y, CGRectGetWidth(yourView.frame),  CGRectGetHeight(yourView.frame)); 
     }
     [gesture setTranslation:CGPointZero yourView];//important to set this 

 }

П.С. Використовуйте блок стану жесту для ініціації, панорамування, видалення. тобто UIGestureRecognizerStateBegan UIGestureRecognizerStateChanged UIGestureRecognizerStateEnded

0
додано
IT KPI iOS
IT KPI iOS
74 учасників

Чат обсуждения IOS. - Оффтоп, флуд, оскорбления и вбросы здесь не приняты. - За нарушение - предупреждение или mute на неделю. - За спам и рекламу - ban. Все чаты IT KPI: https://t.me/itkpi/602

ios_jobs_ua
ios_jobs_ua
27 учасників

Mobile Dev Jobs UA
Mobile Dev Jobs UA
20 учасників

Публикуем вакансии и запросы на поиск работы по направлению iOS, Android, Xamarin, RN и т.д.