IT Share you

UIViewController로 다시 팝업 된 후 UIScrollView의 원점이 변경됩니다.

shareyou 2020. 12. 14. 21:06
반응형

UIViewController로 다시 팝업 된 후 UIScrollView의 원점이 변경됩니다.


다양한 하위보기 UIViewController를 포함하는 스토리 보드의 장면 으로 하위 클래스가 UIScrollView있습니다. 하위보기 중 하나는 UIButton다른 장면 UIViewController하위 클래스 로 연결되는 입니다. 내가보기에서 돌아올 때 (팝업 UIViewController있지만, 나는 스크롤 뷰의 기원은 어떻게 든 변경된 것을 알게 탐색 컨트롤러 스택 오프) contentsizecontentoffset올바른 보인다.

또한 흥미로운 점은 앱에 탭 바가 있고 탭에서 해당 뷰로 돌아갈 때 스크롤 뷰가 (0, 0) 오프셋으로 올바르게 다시 설정된다는 것입니다.

스토리 보드에 거의 모든 것이 있기 때문에 기본적으로이 프로세스에 관련된 코드는 없습니다. 나는 스토리 보드를 사용하는 데 상당히 익숙하기 때문에 나는 무엇을 모르지만 내가 뭔가 잘못하고 있다고 생각한다. 그것이 무엇인지에 대한 아이디어가 있습니까? 크기 문제 또는 제약 사항이 있습니까?


iOS 7/8/9에서는 self.automaticallyAdjustsScrollViewInsets = NO;제 경우에 문제가 간단하게 해결되었습니다.


다시 팝업 뷰 컨트롤러의 viewWillAppear에서 이것을 시도하십시오.

 self.scrollView.contentOffset = CGPointMake(0, 0);

편집 : Peter의 코드를 추가 할 때 다음과 같이 최상의 결과를 얻을 수 있습니다.

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:YES];
    self.scrollView.contentOffset = CGPointMake(0, 0);
}

...을 더한

- (void)viewWillDisappear:(BOOL)animated {  
    self.recentContentOffset = self.scrollView.contentOffset;
    [super viewWillDisappear:animated];
}

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    self.scrollView.contentOffset = CGPointMake(0, self.recentContentOffset.y);
}

원래 스크롤 위치로 돌아가고 시각적 부작용이 없으며 스크롤 뷰 자체가 다시 돌아온 후 수퍼 뷰 (문제)에 올바르게 배치됩니다.


사실, 저는 그 코드 줄을에 넣고 viewDidDisappear뷰가 다시 나타날 때 오프셋을 기억하도록이 줄을 그 앞에 추가했습니다.

 self.contentOffset = self.scrollView.contentOffset;

만큼 잘

 - (void)viewDidLayoutSubviews { 
       self.scrollView.contentOffset = self.contentOffset; 
 }

비슷한 문제가 발생하여 viewController를 닫은 후 내 tableView의 contentOffset이 (0, -64)로 변경되었습니다.

내 솔루션은 약간 이상했습니다. 다른 모든 답변을 시도했지만 성공하지 못했습니다. 내 문제를 해결 한 유일한 방법은 .xib의 컨트롤 트리에서 tableView 위치를 전환하는 것입니다.

다음과 같은 상위 뷰의 첫 번째 컨트롤입니다.

전에

ImageView 바로 뒤에 tableView를 옮겼고 작동했습니다.

후

테이블 뷰를 첫 번째 위치에 놓는 것이 문제를 일으키는 것으로 보이며 테이블 뷰를 다른 위치로 이동하면 문제가 해결되었습니다.

PD 나는 autoLayout도 스토리 보드를 사용하지 않는다

이것이 누군가를 도울 수 있기를 바랍니다!


collectionView를 사용하고 있는데 비슷한 문제가 있습니다. iOS 11의 경우 크기 검사기에 "내용 삽입"이 있습니다. "Never"로 설정하십시오. 그것은 나를 위해 문제를 해결했습니다. 누군가에게 도움이되기를 바랍니다.

목표 C :

if (@available(iOS 11, *)) {
   [UIScrollView appearance].contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}

빠른:

if #available(iOS 11, *) {
UIScrollView.appearance().contentInsetAdjustmentBehavior = .never
}

iOS 11에서는 뷰 컨트롤러를 띄운 후 돌아올 때 이전 뷰 컨트롤러의 테이블 뷰가 콘텐츠 삽입을 자동으로 조정하는 데 사용되어 테이블 뷰 콘텐츠가 갑자기 위쪽에서 점프하는 유사한 문제에 직면했습니다. 다음 솔루션은 iOS 11에서 저에게 효과적이었습니다.

Storyboard에서 tableview를 선택하고 Attributes inspector로 이동하여 Row Height 및 Estimate 필드에 대해 "자동"을 선택 취소하십시오. 또한 내용 삽입을 "자동"에서 "안함"으로 변경하십시오.

[ 테이블보기]


불행히도 Peter와 MacMark의 제안은 저에게 효과가 없었습니다 (자동 레이아웃이있는 Xcode 5). 해결책은 스토리 보드로 이동하여 뷰 컨트롤러를 선택하고 Reset to Suggested Constraints in View Controller.

여기에 이미지 설명 입력


최근 비슷한 문제에 대한 질문을 게시했지만 다른 맥락에서 : 모달 뷰 컨트롤러를 닫은 후 프레임이 자동 레이아웃 제약을 반영하지 않습니다.

제 경우에는 스크롤 뷰 자체의 원점이 아니라 스크롤 뷰 내부의 사용자 정의 컨테이너 뷰의 원점이 옮겨졌습니다. 자동 레이아웃과 관련하여 사용자 지정 컨테이너보기는 스크롤보기의 네면에 고정됩니다.

컨테이너보기는 IB가 아닌 프로그래밍 방식으로 생성 및 구성됩니다. 컨테이너보기의 제약 조건은 변경되지 않았지만 컨테이너보기의 원점은 모달보기 컨트롤러를 해제 한 후 대체됩니다. 제약과 프레임 사이의 이러한 단절은 설명 할 수 없습니다.

더욱 놀라운 점은 관련된 모든 제약을 제거하고 다시 추가 한 후에도 원점 변위 문제가 남아 있다는 것입니다.

비슷한 해결책을 찾았습니다. 현재 콘텐츠 오프셋 값을 저장하고 콘텐츠 오프셋을 "0"으로 설정 한 다음 시스템이 뷰를 교체하도록 한 다음 콘텐츠 오프셋을 복원합니다 (예 : 콘텐츠 오프셋 댄스).

그러나 제 경우에는 문제를 해결하기 위해 추가 조치를 취해야했습니다. 내 스크롤 뷰는 tilePages 메서드에서 하위 뷰를 가져 오는 페이징 스크롤 뷰입니다 (이전 WWDC 비디오에서 설명 됨). 스크롤 뷰의 콘텐츠 오프셋을 변경하면 UIScrollViewDelegate의 scrollViewDidScroll : 메서드를 통해 tilePages 메서드가 트리거됩니다. 콘텐츠 오프셋 댄스를하는 동안 tilePages를 끄는 플래그를 설정해야했습니다. 그렇지 않으면 앱이 충돌합니다.

iOS 7로 업그레이드 할 때 콘텐츠 오프셋 댄스에 대한 코드를 제거 할 수 있기를 바랍니다.


현재 답변을 따를 때 계속되는 문제 :

제시된 뷰 컨트롤러를 떠나지 않고 제시된 뷰 컨트롤러를 여는 두 번째 시도는 문제가 남아 있습니다. 이것이 내 솔루션을 가져온 정확한 단계게시하는 이유 입니다.

  1. 따라서 Storyboard에서 collectionView의 제약 조건을 재설정 하여 이들이 고정 된 ViewController의 메인 뷰에 고정되었는지 확인합니다.

  2. 추가 : 프리젠 테이션 뷰 컨트롤러 self.view.translatesAutoresizingMaskIntoConstraints = YES;내부 viewDidLoad.

  3. 그리고 모달로 표시되는 뷰 컨트롤러의 모양 이전에 컬렉션 뷰의 contentOffset을 비공개로 저장 했습니다.

    (void)viewWillDisappear:(BOOL)animated
    {
        [super viewWillDisappear:animated];
    
        self.contentOffset = self.collectionView.contentOffset;
        self.collectionView.contentOffset = CGPointZero;
    }
    
    - (void)viewDidLayoutSubviews {
         [super viewDidLayoutSubviews];
         self.collectionView.contentOffset = self.contentOffset;
    }
    

최근에이 버그가 발생했습니다. 다음 코드를 사용하여 해결할 수 있습니다.

// fix ios 6 bug begin
- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];

    if ([[[UIDevice currentDevice] systemVersion] floatValue] < 7) {
        isRecoredforios6 = YES;
        recordedOffsetforios6 = self.tableView.contentOffset;
        recordedSizeforios6 = self.tableView.contentSize;
    }
}

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    if (isRecoredforios6) {
        isRecoredforios6 = NO;
        self.tableView.contentSize = recordedSizeforios6;
        self.tableView.contentOffset = recordedOffsetforios6;
    }
}
// fix ios 6 bug end

감사합니다 Peter Jacobs!


- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];

    if ([[[UIDevice currentDevice] systemVersion] floatValue] < 7) {
        _isRecoredforios6 = YES;
        _recordedOffsetforios6 = _scrollView.contentOffset;
        _recordedSizeforios6 = _scrollView.contentSize;
        _scrollView.contentOffset = CGPointZero;
    }

}

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    if (_isRecoredforios6) {
        _isRecoredforios6 = NO;
        _scrollView.contentSize = _recordedSizeforios6;
        _scrollView.contentOffset = _recordedOffsetforios6;
    }
}

이 ios6 버그를 수정했으며 이러한 코드를 사용하여 해결할 수 있습니다. Scrollview에서 발생한 버그를 해결했습니다. 모든 친구들에게 감사합니다!


많은 것을 시도한 후 :

  • 탐색 모음에 문제가 있는지 확인하려면 automaticAdjustsScrollViewInsets를 false로 설정하십시오.
  • 고정 된 셀 높이로 재생 ...
  • 셀 높이 캐싱 중 ...
  • 테이블 뷰 오프셋으로 속성을 유지하고, 캐싱하고, viewWillAppear에 설정합니다.
  • 기타

나는 estimatedRowHeight그것이 ~ 150px이어야 할 때 50px로 설정된 값 에 관한 문제임을 깨달았습니다 . 값을 업데이트하면 문제가 해결되었으며 이제 테이블보기가 동일한 오프셋을 유지합니다.


불투명 막대 아래 가장자리 확장 옵션을 확인해 보셨습니까? 스토리 보드 내부의 컨트롤러 속성 검사기에서 찾을 수 있습니다.

XCode 9 iOS 11을 사용하여 나를 위해 트릭을 수행했습니다.

여기에 이미지 설명 입력


위의 어느 것도 나를 위해 일하지 않았고, 대신 내 사용자 지정 Push / Pull 애니메이션을 수행 할 수 있었고 매력처럼 작동합니다.

먼저 Push 시나리오를 구현하는이 클래스를 추가합니다.

class PushAnimator: NSObject, UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate {

func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
    return 0.5
}

func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {

    // get reference to our fromView, toView and the container view that we should perform the transition in
    let container = transitionContext.containerView
    let fromView = transitionContext.view(forKey: UITransitionContextViewKey.from)!
    let toView = transitionContext.view(forKey: UITransitionContextViewKey.to)!

    // start the toView to the right of the screen
    var frame = toView.frame
    frame.origin.x = container.frame.width
    toView.frame = frame

    // add the both views to our view controller
    container.addSubview(toView)
    container.addSubview(fromView)

    // get the duration of the animation
    let duration = self.transitionDuration(using: transitionContext)

    // perform the animation!
    UIView.animate(withDuration: duration, animations: {

        var frame = fromView.frame
        frame.origin.x = -container.frame.width
        fromView.frame = frame

        toView.frame = container.bounds

    }, completion: { _ in
        // tell our transitionContext object that we've finished animating
        transitionContext.completeTransition(true)

    })
}
}

그런 다음 팝 시나리오를 구현하는이 클래스를 추가하십시오.

import Foundation
import UIKit

class PopAnimator: NSObject, UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate {

func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
    return 0.5
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
    // get reference to our fromView, toView and the container view that we should perform the transition in
    let container = transitionContext.containerView
    let fromView = transitionContext.view(forKey: UITransitionContextViewKey.from)!
    let toView = transitionContext.view(forKey: UITransitionContextViewKey.to)!

    // set up from 2D transforms that we'll use in the animation
    let offScreenRight = CGAffineTransform(translationX: container.frame.width, y: 0)

    // start the toView to the right of the screen
    var frame = toView.frame
    frame.origin.x = -container.frame.width
    toView.frame = frame

    // add the both views to our view controller
    container.addSubview(toView)
    container.addSubview(fromView)

    // get the duration of the animation
    let duration = self.transitionDuration(using: transitionContext)

    // perform the animation!
    UIView.animate(withDuration: duration, animations: {

        fromView.transform = offScreenRight
        toView.frame = container.bounds

    }, completion: { _ in
        // tell our transitionContext object that we've finished animating
        transitionContext.completeTransition(true)

    })
}
}

그런 다음이 줄을 viewDidLoad 메서드에 추가하여 기본 NavigationController Delegate를 변경합니다.

self.navigationController?.delegate = self

그리고 마술을보십시오 :)


나는 모든 곳에 게시 된 다양한 솔루션의 조합을 사용했고이 하위 클래스를 생각 해냈다.

// Keeps track of the recent content offset to be able to restore the
// scroll position when a modal viewcontroller is dismissed
class ScrollViewWithPersistentScrollPosition: UIScrollView {

    // The recent content offset for restoration.
    private var recentContentOffset: CGPoint = CGPoint(x: 0, y: 0)

    override func willMove(toWindow newWindow: UIWindow?) {
        if newWindow != nil {
            // save the scroll offset.
            self.recentContentOffset = self.contentOffset
        }
        super.willMove(toWindow: newWindow)
    }

    override func didMoveToWindow() {
        if self.window != nil {
            // restore the offset.
            DispatchQueue.main.async(execute: {
                // restore it
                self.contentOffset = self.recentContentOffset
            })
        }
        super.didMoveToWindow()
    }
 }

iOS 11.2 / Xcode 9.2에서 테스트되었습니다.


위의 방법 중 어느 것도 도움이되지 않은 경우를 대비하여이 문제가 있었으며 문제는 다음 코드가 있다는 것입니다 ..

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    tableView.reloadData()
}

이 reloadData () 줄을 주석 처리하면 문제가 해결되었습니다. 이 줄이 필요하지 않았기 때문에 왜 추가했는지 모르겠습니다!

이 솔루션이 다른 사람에게 도움이되기를 바랍니다.


AutoLayout그렇지 않으면 해당 xib에 대한 옵션을 해제하십시오 .

참고 URL : https://stackoverflow.com/questions/17404682/uiscrollviews-origin-changes-after-popping-back-to-the-uiviewcontroller

반응형