확대 / 축소 및 스크롤에 사용 하는 UIImageView
내부가 UIScrollView
있습니다. 스크롤보기의 이미지 / 내용이 스크롤보기보다 크면 모든 것이 잘 작동합니다. 그러나 이미지가 스크롤보기보다 작아지면 스크롤보기의 왼쪽 상단에 고정됩니다. 사진 앱과 같이 중앙에 유지하고 싶습니다.
UIScrollView
더 작을 때 중심 의 내용을 유지하는 것에 대한 아이디어 나 예가 있습니까?
iPhone 3.0으로 작업하고 있습니다.
다음 코드는 거의 작동합니다. 최소 확대 / 축소 수준에 도달 한 후 꼬 으면 이미지가 왼쪽 상단으로 돌아갑니다.
- (void)loadView {
[super loadView];
// set up main scroll view
imageScrollView = [[UIScrollView alloc] initWithFrame:[[self view] bounds]];
[imageScrollView setBackgroundColor:[UIColor blackColor]];
[imageScrollView setDelegate:self];
[imageScrollView setBouncesZoom:YES];
[[self view] addSubview:imageScrollView];
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"WeCanDoIt.png"]];
[imageView setTag:ZOOM_VIEW_TAG];
[imageScrollView setContentSize:[imageView frame].size];
[imageScrollView addSubview:imageView];
CGSize imageSize = imageView.image.size;
[imageView release];
CGSize maxSize = imageScrollView.frame.size;
CGFloat widthRatio = maxSize.width / imageSize.width;
CGFloat heightRatio = maxSize.height / imageSize.height;
CGFloat initialZoom = (widthRatio > heightRatio) ? heightRatio : widthRatio;
[imageScrollView setMinimumZoomScale:initialZoom];
[imageScrollView setZoomScale:1];
float topInset = (maxSize.height - imageSize.height) / 2.0;
float sideInset = (maxSize.width - imageSize.width) / 2.0;
if (topInset < 0.0) topInset = 0.0;
if (sideInset < 0.0) sideInset = 0.0;
[imageScrollView setContentInset:UIEdgeInsetsMake(topInset, sideInset, -topInset, -sideInset)];
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return [imageScrollView viewWithTag:ZOOM_VIEW_TAG];
}
/************************************** NOTE **************************************/
/* The following delegate method works around a known bug in zoomToRect:animated: */
/* In the next release after 3.0 this workaround will no longer be necessary */
/**********************************************************************************/
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale {
[scrollView setZoomScale:scale+0.01 animated:NO];
[scrollView setZoomScale:scale animated:NO];
// END Bug workaround
CGSize maxSize = imageScrollView.frame.size;
CGSize viewSize = view.frame.size;
float topInset = (maxSize.height - viewSize.height) / 2.0;
float sideInset = (maxSize.width - viewSize.width) / 2.0;
if (topInset < 0.0) topInset = 0.0;
if (sideInset < 0.0) sideInset = 0.0;
[imageScrollView setContentInset:UIEdgeInsetsMake(topInset, sideInset, -topInset, -sideInset)];
}
답변
매우 간단한 해결책이 있습니다! ScrollViewDelegate를 확대하면서 하위보기의 중앙 (이미지보기)을 업데이트하기 만하면됩니다. 확대 / 축소 된 이미지가 스크롤보기보다 작 으면 subview.center를 조정하고 그렇지 않으면 가운데는 (0,0)입니다.
- (void)scrollViewDidZoom:(UIScrollView *)scrollView
{
UIView *subView = [scrollView.subviews objectAtIndex:0];
CGFloat offsetX = MAX((scrollView.bounds.size.width - scrollView.contentSize.width) * 0.5, 0.0);
CGFloat offsetY = MAX((scrollView.bounds.size.height - scrollView.contentSize.height) * 0.5, 0.0);
subView.center = CGPointMake(scrollView.contentSize.width * 0.5 + offsetX,
scrollView.contentSize.height * 0.5 + offsetY);
}
답변
@EvelynCordner의 답변 은 내 앱에서 가장 잘 작동했습니다. 다른 옵션보다 코드가 훨씬 적습니다.
필요한 경우 Swift 버전이 있습니다.
func scrollViewDidZoom(_ scrollView: UIScrollView) {
let offsetX = max((scrollView.bounds.width - scrollView.contentSize.width) * 0.5, 0)
let offsetY = max((scrollView.bounds.height - scrollView.contentSize.height) * 0.5, 0)
scrollView.contentInset = UIEdgeInsetsMake(offsetY, offsetX, 0, 0)
}
답변
좋아, 나는 지난 이틀 동안이 싸움을하고 마침내 마침내 믿을만한 (지금까지 …) 해결책을 찾았으며 그것을 공유하고 다른 사람들에게 약간의 고통을 덜어 야한다고 생각했습니다. :)이 솔루션에 문제가 있으면 소리 지르십시오!
기본적으로 StackOverflow, Apple 개발자 포럼 검색, three20, ScrollingMadness, ScrollTestSuite 등의 코드를 살펴 보았습니다 .UIScrollView의 오프셋 및 / 또는 삽입과 함께 UIImageView 프레임을 확대하려고했습니다. ViewController 등에서 아무 효과가 없었습니다 (다른 사람들도 알았 듯이).
그것에 자고 난 후, 나는 몇 가지 대안 각도를 시도했다.
- UIImageView를 서브 클래스 화하여 자체 크기를 동적으로 변경합니다. 이는 전혀 효과가 없었습니다.
- UIScrollView를 서브 클래스 화하여 자체 contentOffset을 동적으로 변경합니다. 이것이 나에게 승자 인 것 같습니다.
이 서브 클래 싱 UIScrollView 메서드를 사용하면 contentOffset 뮤 테이터를 재정의하므로 이미지가 뷰포트보다 작게 조정될 때 {0,0}으로 설정되지 않습니다. 대신 이미지가 뷰포트의 중앙에 유지되도록 오프셋을 설정합니다. 지금까지는 항상 작동하는 것 같습니다. 넓고, 크고, 작고 큰 이미지로 확인했으며 “작동하지만 최소 확대 / 축소로 핀치가 끊어집니다”문제가 없습니다.
이 솔루션을 사용하는 예제 프로젝트를 github에 업로드했습니다. http://github.com/nyoron/NYOBetterZoom
답변
이 코드는 대부분의 iOS 버전에서 작동해야하며 3.1 이상에서 작동하도록 테스트되었습니다.
포토 콜러 용 Apple WWDC 코드를 기반으로합니다.
아래를 UIScrollView의 하위 클래스에 추가하고 tileContainerView를 이미지 또는 타일이 포함 된 뷰로 바꾸십시오.
- (void)layoutSubviews {
[super layoutSubviews];
// center the image as it becomes smaller than the size of the screen
CGSize boundsSize = self.bounds.size;
CGRect frameToCenter = tileContainerView.frame;
// center horizontally
if (frameToCenter.size.width < boundsSize.width)
frameToCenter.origin.x = (boundsSize.width - frameToCenter.size.width) / 2;
else
frameToCenter.origin.x = 0;
// center vertically
if (frameToCenter.size.height < boundsSize.height)
frameToCenter.origin.y = (boundsSize.height - frameToCenter.size.height) / 2;
else
frameToCenter.origin.y = 0;
tileContainerView.frame = frameToCenter;
}
답변
자동 레이아웃을 사용하는 스크롤보기에 더 적합한 솔루션을 보려면 스크롤보기 하위보기의 프레임을 업데이트하는 대신 스크롤보기의 내용 삽입을 사용하십시오.
- (void)scrollViewDidZoom:(UIScrollView *)scrollView
{
CGFloat offsetX = MAX((scrollView.bounds.size.width - scrollView.contentSize.width) * 0.5, 0.0);
CGFloat offsetY = MAX((scrollView.bounds.size.height - scrollView.contentSize.height) * 0.5, 0.0);
self.scrollView.contentInset = UIEdgeInsetsMake(offsetY, offsetX, 0.f, 0.f);
}
답변
현재 나는에 기반하여 오프셋을 조정하기 위해 서브 클래스 화 UIScrollView
및 재정의 중 setContentOffset:
입니다 contentSize
. 핀치 및 프로그래밍 방식의 확대 / 축소 모두에서 작동합니다.
@implementation HPCenteringScrollView
- (void)setContentOffset:(CGPoint)contentOffset
{
const CGSize contentSize = self.contentSize;
const CGSize scrollViewSize = self.bounds.size;
if (contentSize.width < scrollViewSize.width)
{
contentOffset.x = -(scrollViewSize.width - contentSize.width) / 2.0;
}
if (contentSize.height < scrollViewSize.height)
{
contentOffset.y = -(scrollViewSize.height - contentSize.height) / 2.0;
}
[super setContentOffset:contentOffset];
}
@end
이 코드는 짧고 달콤 할뿐만 아니라 @Erdemus 솔루션보다 훨씬 부드러운 확대 / 축소를 생성합니다. RMGallery 데모 에서 실제로 작동하는 것을 볼 수 있습니다 .
답변
나는이 문제와 싸우는 데 하루를 보냈고 결국에는 scrollViewDidEndZooming : withView : atScale : 을 다음과 같이 .
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale {
CGFloat screenWidth = [[UIScreen mainScreen] bounds].size.width;
CGFloat screenHeight = [[UIScreen mainScreen] bounds].size.height;
CGFloat viewWidth = view.frame.size.width;
CGFloat viewHeight = view.frame.size.height;
CGFloat x = 0;
CGFloat y = 0;
if(viewWidth < screenWidth) {
x = screenWidth / 2;
}
if(viewHeight < screenHeight) {
y = screenHeight / 2 ;
}
self.scrollView.contentInset = UIEdgeInsetsMake(y, x, y, x);
}
이렇게하면 이미지가 화면보다 작을 때 이미지 주위에 충분한 공간이있어 원하는 위치에 이미지를 배치 할 수 있습니다.
(UIScrollView에 이미지를 보유 할 UIImageView가 포함되어 있다고 가정)
본질적으로 이것이하는 일은 이미지보기의 너비 / 높이가 화면의 너비 / 높이보다 작은 지 확인하고 그렇다면 화면 너비 / 높이의 절반을 삽입하십시오 (이미지를 원한다면이 크기를 더 크게 만들 수 있습니다) 화면 경계를 벗어납니다).
이것은 UIScrollViewDelegate 메소드이므로 빌드 문제가 발생하지 않도록 뷰 컨트롤러의 선언에 추가하는 것을 잊지 마십시오.