จัดกึ่งกลางเนื้อหาของ UIScrollView เมื่อเล็กลง


140

ฉันมีส่วนUIImageViewในUIScrollViewที่ฉันใช้สำหรับซูมและเลื่อน หากรูปภาพ / เนื้อหาของมุมมองเลื่อนใหญ่กว่ามุมมองเลื่อนทุกอย่างทำงานได้ดี อย่างไรก็ตามเมื่อภาพมีขนาดเล็กกว่ามุมมองเลื่อนภาพจะติดที่มุมซ้ายบนของมุมมองเลื่อน ฉันต้องการให้มันอยู่กึ่งกลางเช่นแอพ Photos

ความคิดหรือตัวอย่างเกี่ยวกับการรักษาเนื้อหาของ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)];
}

คุณเคยแก้ปัญหานี้อย่างสมบูรณ์หรือไม่? ฉันกำลังดิ้นรนกับปัญหาเดียวกัน
Jonah

1
ข้อควรสนใจ: ใช้ค่า initialZoom เพื่อคำนวณสิ่งที่ใส่เข้าไปหากไม่ใช่ค่าเดียว (ไม่มีการซูม) เช่นใช้บรรทัดเหล่านี้: float topInset = (maxSize.height - imageSize.height * initialZoom) / 2.0; float sideInset = (maxSize.width - imageSize.width * initialZoom) / 2.0; และในที่สุดก็ตั้งค่าการซูมเริ่มต้น [imageScrollView setZoomScale: initialZoom];
เฟลิกซ์

คำตอบ:


228

ฉันมีทางออกที่ง่ายมาก! สิ่งที่คุณต้องใช้คืออัปเดตจุดศูนย์กลางของมุมมองย่อย (ภาพมุมมอง) ขณะซูมเข้า ScrollViewDelegate หากภาพที่ซูมมีขนาดเล็กกว่า scrollview ให้ปรับ 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);
}

5
สำหรับฉันแล้วโซลูชันนี้มีความกระตุกมากกว่าการใช้ NYOBetterZoom ของ Liam อาจจะขึ้นอยู่กับขนาดภาพ ฯลฯ คุณธรรม; ใช้โซลูชันที่เหมาะสมกับความต้องการของคุณมากที่สุด
wuf810

2
Stackoverflow GOLD STAR สำหรับสิ่งนี้ ฉันกำลังดิ้นรนกับสิ่งนี้ แต่วิธีแก้ปัญหานั้นง่ายมาก
n13

2
เพื่อทำให้ง่ายขึ้นเล็กน้อย:CGFloat offsetX = MAX((scrollView.bounds.size.width - scrollView.contentSize.width) * 0.5, 0.0);
Marek R

6
การปรับนี้ช่วยฉันได้เมื่อ scrollview มีสิ่งที่ใส่เข้าไป: CGFloat offsetX = MAX((scrollView.bounds.size.width - scrollView.contentInset.left - scrollView.contentInset.right - scrollView.contentSize.width) * 0.5, 0.0); CGFloat offsetY = MAX((scrollView.bounds.size.height - scrollView.contentInset.top - scrollView.contentInset.bottom - scrollView.contentSize.height) * 0.5, 0.0);
Kieran Harper

3
ผมสังเกตเห็นว่านี้เช่นเทคนิคกลางอื่น ๆ zoomToRect:อีกมากมายที่ดูเหมือนว่าจะประสบปัญหาเมื่อใช้ การใช้contentInsetวิธีการนี้ใช้งานได้ดีกว่าหากคุณต้องการฟังก์ชั่นนั้น ดูpetersteinberger.com/blog/2013/how-to-center-uiscrollviewสำหรับรายละเอียดเพิ่มเติม
Matej Bukovinski

52

@ คำตอบของ 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)
}

4
อันนี้ใช้งานได้ดี! มุมมองที่เคลื่อนไหวแม้อย่างถูกต้องหลังจากหดตัว
Carter Medlin

4
ฉันใส่รหัสนี้ใน func และเรียกมันว่าในviewDidLayoutSubviewsเพื่อให้แน่ใจว่ามันถูกตั้งค่าอย่างถูกต้องในตอนแรก
Carter Medlin

การโทรที่ดี @CarterMedlin ช่วยฉันได้มากเมื่อโหลดครั้งแรกของ Swift 3
AJ Hernandez

ดูเหมือนว่าจะใช้งานได้ แต่ฉันไม่เข้าใจว่าทำไมเพราะดูเหมือนจะคำนวณสิ่งที่เหมือนกันเสมอ: ขอบเขตของมุมมองการเลื่อนได้รับการแก้ไขเช่นเดียวกับขนาดเนื้อหา
Vaddadi Kartick

เนื้อหาเปลี่ยนแปลงขนาดเมื่อซูมขนาดเลื่อนดูได้รับการแก้ไขเท่านั้น
Michał Ziobro

25

โอเคฉันได้ต่อสู้กับสิ่งนี้ในช่วงสองวันที่ผ่านมาและในที่สุดก็มาถึงวิธีการแก้ปัญหาที่น่าเชื่อถือ (จนถึงตอนนี้ ... ) ฉันคิดว่าฉันควรแบ่งปันและช่วยคนอื่นให้เจ็บปวดบ้าง :) หากคุณพบปัญหาเกี่ยวกับวิธีแก้ไขปัญหานี้โปรดตะโกน!

โดยทั่วไปฉันได้ผ่านสิ่งที่ทุกคนมีแล้ว: การค้นหา StackOverflow, Apple Developer Forums, ดูรหัสสำหรับสาม, ScrollingMadness, ScrollTestSuite, และอื่น ๆ ฉันได้ลองขยายเฟรม UIImageView, เล่นกับ UIScrollView ของ offset และ / หรือ insets จาก ViewController ฯลฯ แต่ไม่มีอะไรที่ใช้งานได้ดีมาก

หลังจากนอนหลับไปแล้วฉันลองทำมุมที่สอง:

  1. การจัดคลาสย่อย UIImageView เพื่อให้มีการเปลี่ยนแปลงขนาดของมันเองแบบไดนามิก - มันไม่ได้ผลเลย
  2. การแบ่งคลาส UIScrollView เพื่อให้มีการเปลี่ยนแปลง contentOffset ของตัวเองแบบไดนามิก - นี่เป็นสิ่งที่ดูเหมือนจะเป็นผู้ชนะสำหรับฉัน

ด้วยวิธีการจัดคลาสย่อยนี้ UIScrollView ฉันกำลังแทนที่ mutor contentOffset ดังนั้นจึงไม่ได้ตั้งค่า {0,0} เมื่อภาพถูกปรับขนาดให้เล็กกว่าวิวพอร์ต - แต่เป็นการตั้งค่าออฟเซ็ตเพื่อให้ภาพถูกจัดกึ่งกลางในวิวพอร์ต จนถึงตอนนี้ดูเหมือนว่าจะทำงานเสมอ ฉันได้ตรวจสอบกับภาพที่มีความกว้างสูงขนาดเล็กและขนาดใหญ่และไม่มีปัญหา "การทำงาน แต่บีบที่การย่อ / ขยายน้อยที่สุด"

ฉันได้อัปโหลดตัวอย่างโครงการไปยัง Github ที่ใช้โซลูชันนี้คุณสามารถค้นหาได้ที่นี่: http://github.com/nyoron/NYOBetterZoom


2
สำหรับผู้ที่สนใจ - ฉันได้อัปเดตโปรเจ็กต์ที่เชื่อมโยงข้างต้นแล้วดังนั้นจึงไม่ค่อยพึ่งพา ViewController ในการทำ 'สิ่งที่ถูกต้อง' UIScrollView ที่กำหนดเองนั้นดูแลรายละเอียดมากขึ้น
เลียมโจนส์

2
เลียมคุณร็อค ฉันกำลังพูดถึงสิ่งนี้ในฐานะผู้เขียน ScrollingMadness BTW บน iPad ในการตั้งค่าเนื้อหามากกว่า 3.2+ ค่าใน scrollViewDidZoom (วิธีการมอบหมายใหม่ 3.2+) Just Works
Andrey Tarantsov

โค้ดที่เรียบร้อยมาก ฉันเกาหัวกับสิ่งนี้มาระยะหนึ่งแล้ว เพิ่มโครงการในhandyiphonecode.com
samvermette

มันเยี่ยมมาก ขอบคุณ. มันไม่ชดเชย UIStatusBar ของฉัน แต่ฉันถูกซ่อนดังนั้นฉันเปลี่ยนบรรทัดanOffset.y = -(scrollViewSize.height - zoomViewSize.height) / 2.0เป็นanOffset.y = (-(scrollViewSize.height - zoomViewSize.height) / 2.0) + 10;
Gordon Fontenot

วิธีการแก้ปัญหาให้สอง Erdemus ง่ายมากในความคิดของฉัน
gyozo kudor

23

รหัสนี้ควรใช้ได้กับ iOS เกือบทุกรุ่น (และผ่านการทดสอบแล้วว่าสามารถใช้งานได้ตั้งแต่ 3.1 ขึ้นไป)

มันขึ้นอยู่กับรหัส WWDC ของ Apple สำหรับช่างถ่ายภาพ

เพิ่มด้านล่างลงในคลาสย่อยของ 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;
}

3
นี่ควรเป็นคำตอบที่ยอมรับได้ง่ายกว่า ขอบคุณ คุณช่วยชีวิตฉัน!!!!!! : D
Duck

หลังจากลบการเรียกใช้ iOS 3.2+ API ทั้งหมดแล้วตรรกะการอยู่ตรงกลางดูเหมือนว่าจะใช้งานได้กับอุปกรณ์ที่ใช้ iOS 3.2 ขึ้นไปเท่านั้นและไม่ใช่ 3.1.3 (น่ากลัวสั่นไหวได้รับการชดเชยแบบสุ่ม) ฉันได้เปรียบเทียบผลลัพธ์ของการกำเนิดเฟรมและขนาดระหว่าง 3.1.3 และ 3.2+ และแม้ว่าจะตรงกันด้วยเหตุผลบางประการมุมมองลูกยังคงได้รับการวางตำแหน่งไม่ถูกต้อง แปลกมาก. คำตอบของ Liam Jone นั้นได้ผลสำหรับฉัน
เดวิดเอช

1
ทั้งสอง @Erdemus และ @JosephH การแก้ปัญหาการทำงาน แต่UIScrollViewวิธีที่นิยม subclass ดูเหมือนว่ามันจะเรียกเมื่อมุมมองจะปรากฏขึ้นเป็นครั้งแรก + อย่างต่อเนื่องในขณะที่การซูมที่อยู่ในความคืบหน้า (ในขณะที่scrollViewDidZoomมีการเรียกใช้เพียงครั้งเดียวต่อการเลื่อนและตามความเป็นจริง)
SwiftArchitect

22

สำหรับวิธีแก้ปัญหาที่เหมาะสำหรับมุมมองแบบเลื่อนที่ใช้การกำหนดเวลาอัตโนมัติให้ใช้ส่วนแทรกเนื้อหาของมุมมองแบบเลื่อนแทนที่จะอัปเดตเฟรมของการดูย่อยของมุมมองการเลื่อนของคุณ

- (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);
}

1
สิ่งนี้ใช้ได้ผลสำหรับฉัน แต่ถ้าภาพมีขนาดเล็กลงเพื่อเริ่มต้นด้วยรหัสนี้ (เมื่อเรียกโดยตรง) อย่างใดไม่ได้อัปเดตแถบเลื่อน สิ่งที่ต้องทำในสิ่งที่ฉันจำเป็นต้องเป็นคนแรกที่ใส่UIViewที่อยู่ภายในUIScrollviewไปยังศูนย์เดียวกัน ( view.center = scrollview.center;) จากนั้นในscrollViewDidZoomการตั้งค่าview.frame.origin xและyการ0อีกครั้ง
morksinaanab

ทำงานได้ดีสำหรับฉันเช่นกัน แต่ฉันทำdispatch_asyncคิวหลักviewWillAppearที่ฉันโทรscrollViewDidZoom:ในมุมมองเลื่อนหลักของฉัน สิ่งนี้ทำให้มุมมองปรากฏด้วยภาพที่อยู่กึ่งกลาง
ปาสกาล

โทรออกรหัสนี้viewDidLayoutSubviewsเพื่อให้แน่ใจว่าได้ตั้งค่าไว้อย่างถูกต้องเมื่อมุมมองแสดงเป็นครั้งแรก
Carter Medlin

21

ขณะนี้ฉันกำลัง subclassing 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


6
คุณไม่จำเป็นต้องใช้คลาสย่อย UIScrollView เพื่อใช้วิธีนี้ Apple ช่วยให้คุณเห็นเหตุการณ์การเลื่อนและซูมในวิธีการมอบหมาย โดยเฉพาะ: - (เป็นโมฆะ) scrollViewDidZoom: (UIScrollView *) scrollView;
Rog

1
ทางออกที่ดีที่สุดที่ฉันเคยเห็น (ทำงานแม้ในขณะที่ใช้ข้อ จำกัด )
Frizlab

12

ฉันใช้เวลาหนึ่งวันในการต่อสู้กับปัญหานี้และจบลงด้วยการใช้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อย่าลืมเพิ่มลงในการประกาศของตัวควบคุมมุมมองของคุณเพื่อหลีกเลี่ยงปัญหาการสร้าง


7

Apple ได้เปิดตัววิดีโอเซสชัน WWDC 2010 ให้กับสมาชิกทุกคนของโปรแกรมผู้พัฒนา iphone หนึ่งในหัวข้อที่กล่าวถึงคือวิธีที่พวกเขาสร้างแอพรูปภาพ !!! พวกเขาสร้างแอปทีละขั้นตอนคล้ายกันมากและทำให้โค้ดทั้งหมดนั้นมีให้ใช้ฟรี

มันไม่ได้ใช้ api ส่วนตัวเช่นกัน ฉันไม่สามารถใส่รหัสใด ๆ ที่นี่เนื่องจากข้อตกลงการไม่เปิดเผย แต่นี่คือลิงค์ไปยังตัวอย่างรหัสดาวน์โหลด คุณอาจจะต้องเข้าสู่ระบบเพื่อเข้าถึง

http://connect.apple.com/cgi-bin/WebObjects/MemberSite.woa/wa/getSoftware?code=y&source=x&bundleID=20645

และนี่คือลิงค์ไปยังหน้า iTunes WWDC:

http://insideapple.apple.com/redir/cbx-cgi.do?v=2&la=en&lc=&a=kGSol9sgPHP%2BtlWtLp%2BEP%2FnxnZarjWJglPBZRHd3oDbACudP51JNGS8KlsFgxZto9X%2BTsnqSbeUSWX0doe%2Fzv%2FN5XV55%2FomsyfRgFBysOnIVggO%2Fn2p%2BiweDK%2F%2FmsIXj


1
ตัวอย่างที่เป็นปัญหาคือ MyImagePicker และมันแสดงให้เห็นถึงปัญหาเดียวกันนี้อย่างสนุกสนาน
โคลินบาร์เร็ตต์

1
ฉันควรจะชัดเจนมากขึ้น ตัวอย่างที่เป็นปัญหาคือ "PhotoScroller" ไม่ใช่ "MyImagePicker" คุณถูกต้องที่ "MyImagePicker" ทำงานไม่ถูกต้อง แต่ "PhotoScroller" ทำ ลองมัน.
โยนาห์

คุณจำชื่อวิดีโอ WWDC ที่พวกเขาพูดคุยเกี่ยวกับ Photoscroller ได้ไหม?
Grzegorz Adam Hankiewicz

1
มันเรียกว่า "การออกแบบแอพที่มีมุมมองเลื่อน"
Jonah

2

ตกลงวิธีนี้ใช้ได้สำหรับฉัน ฉันมีคลาสย่อยที่UIScrollViewมีการอ้างอิงถึงUIImageViewมันกำลังแสดงอยู่ เมื่อใดก็ตามที่การUIScrollViewซูมคุณสมบัติ contentSize ถูกปรับ มันอยู่ในตัวตั้งค่าที่ฉันปรับขนาดUIImageViewอย่างเหมาะสมและปรับตำแหน่งกึ่งกลาง

-(void) setContentSize:(CGSize) size{
CGSize lSelfSize = self.frame.size;
CGPoint mid;
if(self.zoomScale >= self.minimumZoomScale){
    CGSize lImageSize = cachedImageView.initialSize;
    float newHeight = lImageSize.height * self.zoomScale;

    if (newHeight < lSelfSize.height ) {
        newHeight = lSelfSize.height;
    }
    size.height = newHeight;

    float newWidth = lImageSize.width * self.zoomScale;
    if (newWidth < lSelfSize.width ) {
        newWidth = lSelfSize.width;
    }
    size.width = newWidth;
    mid = CGPointMake(size.width/2, size.height/2);

}
else {
    mid = CGPointMake(lSelfSize.width/2, lSelfSize.height/2);
}

cachedImageView.center = mid;
[super  setContentSize:size];
[self printLocations];
NSLog(@"zoom %f setting size %f x %f",self.zoomScale,size.width,size.height);
}

เมื่อเวลาผ่านไปฉันตั้งค่าภาพบนUIScrollViewฉันปรับขนาด UIScrollViewใน scrollview ยังเป็นชั้นเองที่ฉันสร้างขึ้น

-(void) resetSize{
    if (!scrollView){//scroll view is view containing imageview
        return;
    }

    CGSize lSize = scrollView.frame.size;

    CGSize lSelfSize = self.image.size; 
    float lWidth = lSize.width/lSelfSize.width;
    float lHeight = lSize.height/lSelfSize.height;

    // choose minimum scale so image width fits screen
    float factor  = (lWidth<lHeight)?lWidth:lHeight;

    initialSize.height = lSelfSize.height  * factor;
    initialSize.width = lSelfSize.width  * factor;

    [scrollView setContentSize:lSize];
    [scrollView setContentOffset:CGPointZero];
    scrollView.userInteractionEnabled = YES;
}

ด้วยสองวิธีนี้ฉันสามารถมีมุมมองที่ทำงานเหมือนกับแอพรูปภาพ


นี่ดูเหมือนจะเป็นการหลอกลวงและมันก็เป็นวิธีแก้ปัญหาที่ค่อนข้างง่าย การเปลี่ยนการซูมบางอย่างไม่สมบูรณ์แบบ แต่ฉันเชื่อว่าสามารถแก้ไขได้ ฉันจะทดลองเพิ่มเติม
hpique

การแก้ปัญหานั้นชัดเจนก่อนการอัพเดท ตอนนี้มันค่อนข้างสับสน คุณช่วยอธิบายได้ไหม
hpique

2

วิธีที่ฉันทำสิ่งนี้คือการเพิ่มมุมมองพิเศษลงในลำดับชั้น:

UIScrollView -> UIView -> UIImageView

ให้คุณUIViewอัตราส่วนเดียวกับคุณUIScrollViewและศูนย์ของคุณUIImageViewลงใน


ขอบคุณ hatfinch จะลองแบบนี้เช่นกัน คุณสามารถโพสต์โค้ดตัวอย่างหรือเปลี่ยนรหัสตัวอย่างของฉันเพื่อแสดงวิธีสร้างลำดับชั้นการดู
hpique

งานประเภทนี้ ยกเว้นความจริงที่ว่าเพราะ UIView คือขนาดของ UIScrollView หากภาพมีขนาดเล็กลง (เช่นแนวนอนแทนที่จะเป็นแนวตั้ง) คุณสามารถเลื่อนภาพบางส่วนออกจากหน้าจอได้ แอปรูปภาพไม่อนุญาตให้ทำสิ่งนี้และดูดีกว่ามาก
Jonah

2

ฉันรู้ว่าคำตอบข้างต้นถูกต้อง แต่ฉันแค่ต้องการให้คำตอบพร้อมคำอธิบายความคิดเห็นจะทำให้คุณเข้าใจว่าทำไมเราจึงทำเช่นนี้

เมื่อฉันโหลด scrollView เป็นครั้งแรกฉันเขียนรหัสต่อไปนี้เพื่อให้อยู่กึ่งกลางโปรดสังเกตว่าเราตั้งค่าไว้contentOffsetก่อนจากนั้นcontentInset

    scrollView.maximumZoomScale = 8
    scrollView.minimumZoomScale = 1

    // set vContent frame
    vContent.frame = CGRect(x: 0,
                            y: 0  ,
                            width: vContentWidth,
                            height: vContentWidth)
    // set scrollView.contentSize
    scrollView.contentSize = vContent.frame.size

    //on the X direction, if contentSize.width > scrollView.bounds.with, move scrollView from 0 to offsetX to make it center(using `scrollView.contentOffset`)
    // if not, don't need to set offset, but we need to set contentInset to make it center.(using `scrollView.contentInset`)
    // so does the Y direction.
    let offsetX = max((scrollView.contentSize.width - scrollView.bounds.width) * 0.5, 0)
    let offsetY = max((scrollView.contentSize.height - scrollView.bounds.height) * 0.5, 0)
    scrollView.contentOffset = CGPoint(x: offsetX, y: offsetY)

    let topX = max((scrollView.bounds.width - scrollView.contentSize.width) * 0.5, 0)
    let topY = max((scrollView.bounds.height - scrollView.contentSize.height) * 0.5, 0)
    scrollView.contentInset = UIEdgeInsets(top: topY, left: topX, bottom: 0, right: 0)

จากนั้นเมื่อฉันหยิก vContent ฉันเขียนรหัสต่อไปนี้เพื่อให้อยู่กึ่งกลาง

func scrollViewDidZoom(_ scrollView: UIScrollView) {
    //we just need to ensure that the content is in the center when the contentSize is less than scrollView.size.
    let topX = max((scrollView.bounds.width - scrollView.contentSize.width) * 0.5, 0)
    let topY = max((scrollView.bounds.height - scrollView.contentSize.height) * 0.5, 0)
    scrollView.contentInset = UIEdgeInsets(top: topY, left: topX, bottom: 0, right: 0)
}

2

หากcontentInsetไม่ต้องการสิ่งใดสิ่งนั้นสามารถใช้เพื่อจัดกึ่งกลางเนื้อหาของ scrollview

class ContentCenteringScrollView: UIScrollView {

    override var bounds: CGRect {
        didSet { updateContentInset() }
    }

    override var contentSize: CGSize {
        didSet { updateContentInset() }
    }

    private func updateContentInset() {
        var top = CGFloat(0)
        var left = CGFloat(0)
        if contentSize.width < bounds.width {
            left = (bounds.width - contentSize.width) / 2
        }
        if contentSize.height < bounds.height {
            top = (bounds.height - contentSize.height) / 2
        }
        contentInset = UIEdgeInsets(top: top, left: left, bottom: top, right: left)
    }
}

ข้อดีหากวิธีนี้คือคุณยังสามารถใช้contentLayoutGuideเพื่อวางเนื้อหาภายใน scrollview

scrollView.addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
    imageView.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor),
    imageView.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor),
    imageView.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor),
    imageView.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor)
])

หรือเพียงแค่ลากและวางเนื้อหาในเครื่องมือสร้างส่วนต่อประสานของ Xcode


1

คุณสามารถดูcontentSizeคุณสมบัติของ UIScrollView (โดยใช้การสังเกตค่าคีย์หรือคล้ายกัน) และปรับอัตโนมัติcontentInsetเมื่อใดก็ตามที่contentSizeการเปลี่ยนแปลงมีค่าน้อยกว่าขนาดของมุมมองเลื่อน


จะพยายาม. สิ่งนี้เป็นไปได้ที่จะทำกับวิธี UIScrollViewDelegate แทนการสังเกต contentSize หรือไม่
hpique

เป็นไปได้มากที่สุด คุณจะใช้- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale(อธิบายไว้ที่developer.apple.com/iphone/library/documentation/UIKit/ ...... ) แต่ฉันต้องการสังเกตcontentSizeเพราะไม่เช่นนั้นคุณจะเลิกใช้การซูมระดับใหม่และค้นหาจากมุมมองต่อไป (ยกเว้นกรณีที่คุณสามารถดึงออกคณิตศาสตร์น่ากลัวบางอย่างขึ้นอยู่กับขนาดของญาติของมุมมองของคุณ.)
ทิม

ขอบคุณทิม scrollViewDidEndZooming เป็นสิ่งที่ฉันใช้ ดูรหัสที่เป็นปัญหา (ฉันได้เพิ่มไว้หลังจากตอบกลับครั้งแรกของคุณ) มันเกือบจะได้ผล ปัญหาเดียวที่ยังคงอยู่ถ้าหากฉันหยิกภาพหลังจากถึงขั้นต่ำ ZoomScale มันจะกลับไปที่มุมซ้ายบน
hpique

คุณหมายถึงว่ามันใช้งานได้ (จัดกึ่งกลางภาพ) สำหรับการจับจากขนาดอื่นที่ไม่ใช่ระดับการซูมขั้นต่ำและจะหยุดถ้าคุณพยายามที่จะบีบอีกครั้งเมื่อคุณอยู่ในระดับต่ำสุด? หรือมันใช้งานไม่ได้กับการบีบให้ถึงระดับต่ำสุดเลยเหรอ?
ทิม

อันแรก มันจัดกึ่งกลางของภาพสำหรับการบีบจากสเกลใด ๆ นอกเหนือจากสเกลการซูมขั้นต่ำสุดและจะแตกถ้าคุณพยายามที่จะบีบอีกครั้งเมื่อคุณอยู่ในสเกลขั้นต่ำ นอกจากนี้เมื่อถึงระดับการซูมขั้นต่ำในครั้งแรกเนื้อหาจะเคลื่อนไหวสั้น ๆ เช่นมาจากด้านบนซึ่งทำให้เกิดผลแปลก ๆ สิ่งนี้เกิดขึ้นกับตัวจำลอง 3.0 อย่างน้อยที่สุด
hpique

1

วิธีหนึ่งที่สวยงามในการจัดเนื้อหาของUISCrollViewสิ่งนี้คือ

เพิ่มผู้สังเกตการณ์หนึ่งคนให้กับขนาดเนื้อหาของคุณUIScrollViewดังนั้นวิธีการนี้จะถูกเรียกทุกครั้งที่มีการเปลี่ยนแปลงเนื้อหา ...

[myScrollView addObserver:delegate 
               forKeyPath:@"contentSize"
                  options:(NSKeyValueObservingOptionNew) 
                  context:NULL];

ตอนนี้ใช้วิธีการสังเกตการณ์ของคุณ:

- (void)observeValueForKeyPath:(NSString *)keyPath   ofObject:(id)object   change:(NSDictionary *)change   context:(void *)context { 

    // Correct Object Class.
    UIScrollView *pointer = object;

    // Calculate Center.
    CGFloat topCorrect = ([pointer bounds].size.height - [pointer viewWithTag:100].bounds.size.height * [pointer zoomScale])  / 2.0 ;
            topCorrect = ( topCorrect < 0.0 ? 0.0 : topCorrect );

    topCorrect = topCorrect - (  pointer.frame.origin.y - imageGallery.frame.origin.y );

    // Apply Correct Center.
    pointer.center = CGPointMake(pointer.center.x,
                                 pointer.center.y + topCorrect ); }
  • [pointer viewWithTag:100]คุณควรเปลี่ยน UIViewเปลี่ยนมุมมองโดยเนื้อหาของคุณ

    • เปลี่ยนการimageGalleryชี้ไปที่ขนาดหน้าต่างของคุณด้วย

การทำเช่นนี้จะแก้ไขศูนย์กลางของเนื้อหาทุกครั้งที่ขนาดของเขาเปลี่ยนไป

หมายเหตุ:UIScrollViewวิธีเดียวที่เนื้อหานี้ไม่ได้ผลดีมากกับการทำงานเป็นซูมมาตรฐานของ


ไม่สามารถใช้งานได้ ดูเหมือนว่าคุณอยู่ตรงกลาง scrollView และไม่ใช่เนื้อหา ทำไมขนาดของหน้าต่างถึงสำคัญ? รหัสไม่ควรแก้ไขตำแหน่ง x ด้วยหรือไม่
hpique

1

นี่เป็นวิธีแก้ปัญหาของฉันสำหรับปัญหาที่ทำงานได้ดีสำหรับมุมมองใด ๆ ภายใน scrollview

-(void)scrollViewDidZoom:(__unused UIScrollView *)scrollView 
    {
    CGFloat top;
    CGFloat left;
    CGFloat bottom;
    CGFloat right;

    if (_scrollView.contentSize.width < scrollView.bounds.size.width) {
        DDLogInfo(@"contentSize %@",NSStringFromCGSize(_scrollView.contentSize));

        CGFloat width = (_scrollView.bounds.size.width-_scrollView.contentSize.width)/2.0;

        left = width;
        right = width;


    }else {
        left = kInset;
        right = kInset;
    }

    if (_scrollView.contentSize.height < scrollView.bounds.size.height) {

        CGFloat height = (_scrollView.bounds.size.height-_scrollView.contentSize.height)/2.0;

        top = height;
        bottom = height;

    }else {
        top = kInset;
        right = kInset;
    }

    _scrollView.contentInset = UIEdgeInsetsMake(top, left, bottom, right);



  if ([self.tiledScrollViewDelegate respondsToSelector:@selector(tiledScrollViewDidZoom:)])
  {
        [self.tiledScrollViewDelegate tiledScrollViewDidZoom:self];
  }
}

1

มีวิธีแก้ไขปัญหามากมายที่นี่ แต่ฉันมีความเสี่ยงที่จะทำให้ที่นี่เป็นของตัวเอง มันดีสำหรับสองเหตุผล: มันไม่ยุ่งเกี่ยวกับประสบการณ์การซูมเช่นเดียวกับการอัพเดตเฟรมมุมมองภาพที่กำลังดำเนินการและยังเคารพสิ่งที่แทรกอยู่ในมุมมองการเลื่อนดูต้นฉบับ (พูดที่กำหนดไว้ใน xib หรือกระดานเรื่องราวสำหรับการจัดการแถบเครื่องมือ .

ก่อนกำหนดผู้ช่วยขนาดเล็ก:

CGSize CGSizeWithAspectFit(CGSize containerSize, CGSize contentSize) {
    CGFloat containerAspect = containerSize.width / containerSize.height,
            contentAspect = contentSize.width / contentSize.height;

    CGFloat scale = containerAspect > contentAspect
                    ? containerSize.height / contentSize.height
                    : containerSize.width / contentSize.width;

    return CGSizeMake(contentSize.width * scale, contentSize.height * scale);
}

ในการเก็บรักษาสิ่งที่แทรกอยู่เดิมฟิลด์ที่กำหนด:

UIEdgeInsets originalScrollViewInsets;

และที่ใดที่หนึ่งใน viewDidLoad ให้เติม:

originalScrollViewInsets = self.scrollView.contentInset;

ในการวาง UIImageView ใน UIScrollView (สมมติว่า UIImage นั้นอยู่ใน loadImage var):

CGSize containerSize = self.scrollView.bounds.size;
containerSize.height -= originalScrollViewInsets.top + originalScrollViewInsets.bottom;
containerSize.width -= originalScrollViewInsets.left + originalScrollViewInsets.right;

CGSize contentSize = CGSizeWithAspectFit(containerSize, loadedImage.size);

UIImageView *imageView = [[UIImageView alloc] initWithFrame:(CGRect) { CGPointZero, contentSize }];
imageView.autoresizingMask = UIViewAutoresizingNone;
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.image = loadedImage;

[self.scrollView addSubview:imageView];
self.scrollView.contentSize = contentSize;

[self centerImageViewInScrollView];

scrollViewDidZoom: จาก UIScrollViewDelegate สำหรับมุมมองเลื่อนนั้น:

- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
    if (scrollView == self.scrollView) {
        [self centerImageViewInScrollView];
    }
}

ในที่สุดศูนย์กลางของตัวเอง:

- (void)centerImageViewInScrollView {
    CGFloat excessiveWidth = MAX(0.0, self.scrollView.bounds.size.width - self.scrollView.contentSize.width),
            excessiveHeight = MAX(0.0, self.scrollView.bounds.size.height - self.scrollView.contentSize.height),
            insetX = excessiveWidth / 2.0,
            insetY = excessiveHeight / 2.0;

    self.scrollView.contentInset = UIEdgeInsetsMake(
            MAX(insetY, originalScrollViewInsets.top),
            MAX(insetX, originalScrollViewInsets.left),
            MAX(insetY, originalScrollViewInsets.bottom),
            MAX(insetX, originalScrollViewInsets.right)
    );
}

ฉันยังไม่ได้ทดสอบการเปลี่ยนแปลงการวางแนว (เช่นปฏิกิริยาที่เหมาะสมสำหรับการปรับขนาด UIScrollView ด้วยตนเอง) แต่การแก้ไขนั้นควรจะค่อนข้างง่าย


1

คุณจะพบว่าโซลูชันที่โพสต์โดย Erdemus ทำงานได้ แต่ ... มีบางกรณีที่เมธอด scrollViewDidZoom ไม่ถูกเรียกใช้ & รูปภาพของคุณติดอยู่ที่มุมซ้ายบน วิธีแก้ปัญหาอย่างง่ายคือการเรียกใช้เมธอดอย่างชัดเจนเมื่อคุณแสดงรูปภาพในครั้งแรกดังนี้

[self scrollViewDidZoom: scrollView];

ในหลายกรณีคุณอาจเรียกใช้วิธีนี้สองครั้ง แต่นี่เป็นวิธีที่สะอาดกว่าคำตอบอื่น ๆ ในหัวข้อนี้


1

ตัวอย่าง Photo Scroller ของ Apple ทำสิ่งที่คุณต้องการอย่างแท้จริง วางสิ่งนี้ใน UIScrollView คลาสย่อยของคุณและเปลี่ยน _zoomView เป็น UIImageView ของคุณ

-(void)layoutSubviews{
  [super layoutSubviews];
  // center the zoom view as it becomes smaller than the size of the screen
  CGSize boundsSize = self.bounds.size;
  CGRect frameToCenter = self.imageView.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;
  }
  self.imageView.frame = frameToCenter; 
}

โค้ดตัวอย่างภาพถ่ายของ Apple


1

หากต้องการทำให้ภาพเคลื่อนไหวลื่นไหลให้ตั้งค่า

self.scrollview.bouncesZoom = NO;

และใช้ฟังก์ชั่นนี้ (ค้นหาศูนย์โดยใช้วิธีที่คำตอบนี้ )

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale {
    [UIView animateWithDuration:0.2 animations:^{
        float offsetX = MAX((scrollView.bounds.size.width-scrollView.contentSize.width)/2, 0);
        float offsetY = MAX((scrollView.bounds.size.height-scrollView.contentSize.height)/2, 0);
        self.imageCoverView.center = CGPointMake(scrollView.contentSize.width*0.5+offsetX, scrollView.contentSize.height*0.5+offsetY);
    }];
}

สิ่งนี้จะสร้างเอฟเฟกต์การสะท้อนกลับ แต่ไม่เกี่ยวข้องกับการเคลื่อนไหวอย่างฉับพลันก่อน


1

เพียงคำตอบที่ได้รับการอนุมัติอย่างรวดเร็ว แต่ไม่มีซับคลาสโดยใช้ตัวแทน

func centerScrollViewContents(scrollView: UIScrollView) {
    let contentSize = scrollView.contentSize
    let scrollViewSize = scrollView.frame.size;
    var contentOffset = scrollView.contentOffset;

    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
    }

    scrollView.setContentOffset(contentOffset, animated: false)
}

// UIScrollViewDelegate    
func scrollViewDidZoom(scrollView: UIScrollView) {
    centerScrollViewContents(scrollView)
}

1

ในกรณี IMAGE ดูภายในของคุณมีความกว้างเฉพาะครั้งแรก (เช่น 300) และคุณเพียงต้องการที่จะอยู่ตรงกลางความกว้างเพียงในการซูมขนาดเล็กกว่าเริ่มต้นของความกว้างอาจช่วยนี้คุณยัง

 func scrollViewDidZoom(scrollView: UIScrollView){
    if imageView.frame.size.width < 300{
        imageView.center.x = self.view.frame.width/2
    }
  }

0

นี่คือวิธีปัจจุบันที่ฉันทำงานนี้ มันดีกว่า แต่ก็ยังไม่สมบูรณ์แบบ ลองตั้งค่า:

 myScrollView.bouncesZoom = YES; 

minZoomScaleในการแก้ไขปัญหาที่มีมุมมองไม่อยู่ตรงกลางเมื่อ

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGSize screenSize = [[self view] bounds].size;//[[UIScreen mainScreen] bounds].size;//
CGSize photoSize = [yourImage size];
CGFloat topInset = (screenSize.height - photoSize.height * [myScrollView zoomScale]) / 2.0;
CGFloat sideInset = (screenSize.width - photoSize.width * [myScrollView zoomScale]) / 2.0;

if (topInset < 0.0)
{ topInset = 0.0; }
if (sideInset < 0.0)
{ sideInset = 0.0; } 
[myScrollView setContentInset:UIEdgeInsetsMake(topInset, sideInset, -topInset, -sideInset)];
ApplicationDelegate *appDelegate = (ApplicationDelegate *)[[UIApplication sharedApplication] delegate];

CGFloat scrollViewHeight; //Used later to calculate the height of the scrollView
if (appDelegate.navigationController.navigationBar.hidden == YES) //If the NavBar is Hidden, set scrollViewHeight to 480
{ scrollViewHeight = 480; }
if (appDelegate.navigationController.navigationBar.hidden == NO) //If the NavBar not Hidden, set scrollViewHeight to 360
{ scrollViewHeight = 368; }

imageView.frame = CGRectMake(0, 0, CGImageGetWidth(yourImage)* [myScrollView zoomScale], CGImageGetHeight(yourImage)* [myScrollView zoomScale]);

[imageView setContentMode:UIViewContentModeCenter];
}

ฉันทำสิ่งต่อไปนี้เพื่อป้องกันไม่ให้ภาพติดด้านข้างหลังจากซูมออก

- (void) scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale {
myScrollView.frame = CGRectMake(0, 0, 320, 420);
 //put the correct parameters for your scroll view width and height above
}

สวัสดีโจนาห์ ดูเหมือนว่าเราจะจัดการกับปัญหาเดียวกันมาระยะหนึ่งแล้ว จะตรวจสอบโซลูชันทั้งสองของคุณและตอบกลับในไม่ช้า
hpique

สวัสดีโจนาห์ฉันพยายามแก้ปัญหาล่าสุดของคุณ อย่างไรก็ตามภาพชั่วคราวคืออะไร ฉันพยายามวาง temporaryImage = imageView.image; อย่างไรก็ตามเมื่อฉันซูมภาพจะหายไป ขอบคุณ Pannag
psanketi

Pannag ชั่วคราวภาพถูกตั้งชื่อไม่ดี มันควรจะเรียกว่า myImage เพราะเป็นเพียงภาพที่คุณใช้ ขอโทษสำหรับความสับสน.
โยนาห์

0

โอเคฉันคิดว่าฉันพบวิธีแก้ปัญหาที่ดีงามแล้ว เคล็ดลับคือการปรับimageView'sเฟรมอย่างต่อเนื่อง ผมพบว่างานนี้ดีกว่าอย่างต่อเนื่องการปรับหรือcontentInsets contentOffSetsฉันต้องเพิ่มรหัสพิเศษเล็กน้อยเพื่อรองรับทั้งแนวตั้งและแนวนอน

นี่คือรหัส:

- (void) scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale {

CGSize screenSize = [[self view] bounds].size;

if (myScrollView.zoomScale <= initialZoom +0.01) //This resolves a problem with the code not working correctly when zooming all the way out.
{
    imageView.frame = [[self view] bounds];
    [myScrollView setZoomScale:myScrollView.zoomScale +0.01];
}

if (myScrollView.zoomScale > initialZoom)
{
    if (CGImageGetWidth(temporaryImage.CGImage) > CGImageGetHeight(temporaryImage.CGImage)) //If the image is wider than tall, do the following...
    {
        if (screenSize.height >= CGImageGetHeight(temporaryImage.CGImage) * [myScrollView zoomScale]) //If the height of the screen is greater than the zoomed height of the image do the following...
        {
            imageView.frame = CGRectMake(0, 0, 320*(myScrollView.zoomScale), 368);
        }
        if (screenSize.height < CGImageGetHeight(temporaryImage.CGImage) * [myScrollView zoomScale]) //If the height of the screen is less than the zoomed height of the image do the following...
        {
            imageView.frame = CGRectMake(0, 0, 320*(myScrollView.zoomScale), CGImageGetHeight(temporaryImage.CGImage) * [myScrollView zoomScale]);
        }
    }
    if (CGImageGetWidth(temporaryImage.CGImage) < CGImageGetHeight(temporaryImage.CGImage)) //If the image is taller than wide, do the following...
    {
        CGFloat portraitHeight;
        if (CGImageGetHeight(temporaryImage.CGImage) * [myScrollView zoomScale] < 368)
        { portraitHeight = 368;}
        else {portraitHeight = CGImageGetHeight(temporaryImage.CGImage) * [myScrollView zoomScale];}

        if (screenSize.width >= CGImageGetWidth(temporaryImage.CGImage) * [myScrollView zoomScale]) //If the width of the screen is greater than the zoomed width of the image do the following...
        {
            imageView.frame = CGRectMake(0, 0, 320, portraitHeight);
        }
        if (screenSize.width < CGImageGetWidth (temporaryImage.CGImage) * [myScrollView zoomScale]) //If the width of the screen is less than the zoomed width of the image do the following...
        {
            imageView.frame = CGRectMake(0, 0, CGImageGetWidth(temporaryImage.CGImage) * [myScrollView zoomScale], portraitHeight);
        }
    }
    [myScrollView setZoomScale:myScrollView.zoomScale -0.01];
}

0

เพียงปิดการใช้เลขหน้าดังนั้นมันจะทำงานได้ดี:

scrollview.pagingEnabled = NO;

0

ฉันมีปัญหาเดียวกันแน่นอน นี่คือวิธีที่ฉันแก้ไข

รหัสนี้ควรจะได้รับเรียกว่าเป็นผลมาจาก scrollView:DidScroll:

CGFloat imageHeight = self.imageView.frame.size.width * self.imageView.image.size.height / self.imageView.image.size.width;
BOOL imageSmallerThanContent = (imageHeight < self.scrollview.frame.size.height) ? YES : NO;
CGFloat topOffset = (self.imageView.frame.size.height - imageHeight) / 2;

// If image is not large enough setup content offset in a way that image is centered and not vertically scrollable
if (imageSmallerThanContent) {
     topOffset = topOffset - ((self.scrollview.frame.size.height - imageHeight)/2);
}

self.scrollview.contentInset = UIEdgeInsetsMake(topOffset * -1, 0, topOffset * -1, 0);

0

แม้ว่าคำถามจะค่อนข้างเก่า แต่ปัญหายังคงมีอยู่ ฉันแก้ไขมันในXcode 7โดยการ จำกัด พื้นที่แนวตั้งของรายการบนสุด (ในกรณีนี้topLabel) ไปที่ superViews (the scrollView) IBOutletและจากนั้นคำนวณค่าคงที่ทุกครั้งที่เนื้อหาเปลี่ยนแปลงตามความสูงของการดูย่อยของ scrollView ( topLabelและbottomLabel)

class MyViewController: UIViewController {

    @IBOutlet weak var scrollView: UIScrollView!
    @IBOutlet weak var topLabel: UILabel!
    @IBOutlet weak var bottomLabel: UILabel!
    @IBOutlet weak var toTopConstraint: NSLayoutConstraint!

    override func viewDidLayoutSubviews() {
        let heightOfScrollViewContents = (topLabel.frame.origin.y + topLabel.frame.size.height - bottomLabel.frame.origin.y)
        // In my case abs() delivers the perfect result, but you could also check if the heightOfScrollViewContents is greater than 0.
        toTopConstraint.constant = abs((scrollView.frame.height - heightOfScrollViewContents) / 2)
    }

    func refreshContents() {
        // Set the label's text …

        self.view.layoutIfNeeded()
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.