iPhone-フル画面UISCROLLVIEWは正しく始まりますが、ナビゲーションバーの下に再配置されます
-
02-10-2019 - |
質問
私は現在、写真アプリのように写真ピッカーを実装しようとしていますが、カスタム画像ソースを使用しています。 「写真スクロール」パートでは、Apple Photoscrollerサンプルコードを使用して適応しました。主な違いの1つは、ナビゲーションコントローラーに埋め込まれていることです(アプリケーションのコントローラーではなく、フォトピッカー独自のNAVコントローラーではなく)ナビゲーションバーがあります。ステータスとナビゲーションバーの半透明があり、Photopickerで使用されているすべてのビューコントローラーでwantsfullscreenlayout = yesを設定しました。ほぼうまくいくようです。 「概要」ビュー(アルバムのすべての写真のサムネイルを表示するもの)は確かにフルスクリーンであり、サムネイルが最初にナビゲーションバーの下に表示されるように手動で相殺する必要があります。ただし、スクロール部分にはグリッチがあります。 Photoscrollerのサンプルコードを知らない人のために、uiscrollview属性(pagingscrollview)を備えたカスタムuiviewcontroller(Photoviewcontroller)と、uiviewとnsintegerger index属性を備えたカスタムuiscrollview(imagescrollview)で動作します。その後、ImagesCrollviewインスタンスは、Photoscrollerのサブビューとして追加/削除されます。
以下はいくつかの関連コードです:
PhotoviewController.H
@interface PhotoViewController : UIViewController <UIScrollViewDelegate> {
UIScrollView *pagingScrollView;
NSMutableSet *recycledPages;
NSMutableSet *visiblePages;
IBOutlet UIToolbar *toolbar;
IBOutlet UIBarButtonItem *previousButtonItem;
IBOutlet UIBarButtonItem *nextButtonItem;
id<PhotoViewDataSource> dataSource;
}
@property(nonatomic, retain) UIScrollView *pagingScrollView;
@property(nonatomic, retain) NSMutableSet *recylcledPages;
@property(nonatomic, retain) NSMutableSet *visiblePages;
@property(nonatomic, retain) UIToolbar *toolbar;
@property(nonatomic, retain) UIBarButtonItem *previousButtonItem;
@property(nonatomic, retain) UIBarButtonItem *nextButtonItem;
@property(nonatomic, retain) id<PhotoViewDataSource> dataSource;
PhotoviewController.M
- (void)loadView
{
self.wantsFullScreenLayout = YES;
// Configure the scrollView
CGRect pagingScrollViewFrame = [self frameForPagingScrollView];
pagingScrollView = [[UIScrollView alloc] initWithFrame:pagingScrollViewFrame];
pagingScrollView.pagingEnabled = YES;
pagingScrollView.backgroundColor = [UIColor redColor];
pagingScrollView.showsVerticalScrollIndicator = NO;
pagingScrollView.showsHorizontalScrollIndicator = NO;
pagingScrollView.contentSize = CGSizeMake(pagingScrollViewFrame.size.width * [self.dataSource imageCount],
pagingScrollViewFrame.size.height);
//pagingScrollView.contentOffset = CGPointMake(0, 0);
pagingScrollView.delegate = self;
self.view = pagingScrollView;
// TODO ? Prepare to tile content
recycledPages = [[NSMutableSet alloc] init];
visiblePages = [[NSMutableSet alloc] init];
[self processPages];
}
- (void)processPages {
// Calculate which pages are visible
CGRect visibleBounds = pagingScrollView.bounds;
NSLog(@"PhotoViewController - processPages : frame = %@", NSStringFromCGRect(pagingScrollView.frame));
NSLog(@"pagingScrollView bounds = %@", NSStringFromCGRect(pagingScrollView.bounds));
NSLog(@"and contentSize = %@", NSStringFromCGSize(pagingScrollView.contentSize));
int firstNeededPageIndex = floorf(CGRectGetMinX(visibleBounds) / CGRectGetWidth(visibleBounds));
int lastNeededPageIndex = floorf((CGRectGetMaxX(visibleBounds)-1) / CGRectGetWidth(visibleBounds));
firstNeededPageIndex = MAX(firstNeededPageIndex, 0);
lastNeededPageIndex = MIN(lastNeededPageIndex, [dataSource imageCount] - 1);
if (lastNeededPageIndex >= 0) {
// Recycle no-longer-visible pages
for (ImageScrollView *page in visiblePages) {
if (page.index < firstNeededPageIndex || page.index > lastNeededPageIndex) {
[recycledPages addObject:page];
[page removeFromSuperview];
}
}
[visiblePages minusSet:recycledPages];
// add missing pages
for (int index = firstNeededPageIndex; index <= lastNeededPageIndex; index++) {
if (![self isDisplayingPageForIndex:index]) {
ImageScrollView *page = [self dequeueRecycledPage];
if (page == nil) {
page = [[[ImageScrollView alloc] init] autorelease];
}
[self configurePage:page forIndex:index];
NSLog(@"PhotoViewController - processPage 2 : bounds = %@", NSStringFromCGRect(pagingScrollView.bounds));
[pagingScrollView addSubview:page];
NSLog(@"PhotoViewController - processPage 3 : bounds = %@", NSStringFromCGRect(pagingScrollView.bounds));
[visiblePages addObject:page];
}
}
}
}
- (ImageScrollView *)dequeueRecycledPage {
ImageScrollView *page = [recycledPages anyObject];
if (page) {
[[page retain] autorelease];
[recycledPages removeObject:page];
}
return page;
}
- (BOOL)isDisplayingPageForIndex:(NSUInteger)index {
BOOL foundPage = NO;
for (ImageScrollView *page in visiblePages) {
if (page.index == index) {
foundPage = YES;
break;
}
}
return foundPage;
}
- (void)configurePage:(ImageScrollView *)page forIndex:(NSUInteger)index {
page.index = index;
page.frame = [self frameForPageAtIndex:index];
NSLog(@"PhotoViewController - configurePage : bounds = %@", NSStringFromCGRect(pagingScrollView.bounds));
[page displayImage:[dataSource imageForImageId:index]];
NSLog(@"PhotoViewController - configurePage 2 : bounds = %@", NSStringFromCGRect(pagingScrollView.bounds));
}
#pragma mark -
#pragma mark ScrollView delegate methods
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
[self processPages];
}
#pragma mark -
#pragma mark Frame calculations
#define PADDING 10
- (CGRect)frameForPagingScrollView {
CGRect frame = [[UIScreen mainScreen] bounds];
frame.origin.x -= PADDING;
frame.size.width += (2*PADDING);
return frame;
}
- (CGRect)frameForPageAtIndex:(NSUInteger)index {
CGRect pagingScrollViewFrame = [self frameForPagingScrollView];
CGRect pageFrame = pagingScrollViewFrame;
pageFrame.size.width -= (2 * PADDING);
pageFrame.origin.x = (pagingScrollViewFrame.size.width * index) + PADDING;
//pageFrame.origin.x = (pagingScrollViewFrame.size.width * index) - (PADDING*index*2);
return pageFrame;
}
ImagesCrollView.H
@interface ImageScrollView : UIScrollView <UIScrollViewDelegate> {
UIView *imageView;
NSUInteger index;
}
@property (assign) NSUInteger index;
- (void)displayImage:(UIImage *)image;
//- (void)displayTiledImageNamed:(NSString *)imageName size:(CGSize)imageSize;
- (void)configureForImageSize:(CGSize)imageSize;
ImagesCrollView.M
- (void)layoutSubviews
{
[super layoutSubviews];
imageView.backgroundColor = [UIColor greenColor];
self.backgroundColor = [UIColor blueColor];
// center the image as it becomes smaller than the size of the screen
CGSize boundsSize = self.bounds.size;
CGRect frameToCenter = 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;
imageView.frame = frameToCenter;
NSLog(@"imageView frame = %@", NSStringFromCGRect(frameToCenter));
if ([imageView isKindOfClass:[TilingView class]]) {
// to handle the interaction between CATiledLayer and high resolution screens, we need to manually set the
// tiling view's contentScaleFactor to 1.0. (If we omitted this, it would be 2.0 on high resolution screens,
// which would cause the CATiledLayer to ask us for tiles of the wrong scales.)
imageView.contentScaleFactor = 1.0;
}
}
#pragma mark -
#pragma mark UIScrollView delegate methods
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return imageView;
}
#pragma mark -
#pragma mark Configure scrollView to display new image (tiled or not)
- (void)displayImage:(UIImage *)image
{
// clear the previous imageView
[imageView removeFromSuperview];
[imageView release];
imageView = nil;
// reset our zoomScale to 1.0 before doing any further calculations
self.zoomScale = 1.0;
// make a new UIImageView for the new image
imageView = [[UIImageView alloc] initWithImage:image];
[self addSubview:imageView];
[self configureForImageSize:[image size]];
}
- (void)configureForImageSize:(CGSize)imageSize
{
CGSize boundsSize = [self bounds].size;
// set up our content size and min/max zoomscale
CGFloat xScale = boundsSize.width / imageSize.width; // the scale needed to perfectly fit the image width-wise
CGFloat yScale = boundsSize.height / imageSize.height; // the scale needed to perfectly fit the image height-wise
CGFloat minScale = MIN(xScale, yScale); // use minimum of these to allow the image to become fully visible
// on high resolution screens we have double the pixel density, so we will be seeing every pixel if we limit the
// maximum zoom scale to 0.5.
CGFloat maxScale = /*1.0 / */[[UIScreen mainScreen] scale];
// don't let minScale exceed maxScale. (If the image is smaller than the screen, we don't want to force it to be zoomed.)
if (minScale > maxScale) {
minScale = maxScale;
}
self.contentSize = imageSize;
self.maximumZoomScale = maxScale;
self.minimumZoomScale = minScale;
self.zoomScale = minScale; // start out with the content fully visible
}
私の問題は、PhotoViewControllerインスタンスを最初にロードしたときに、PagingScrollViewが(0、-64)ピクセル(ステータスバー +ナビゲーションバーの高さ)の起源に相殺されていることです。これにより、ImagesCrollviewがNAVバー(Origin(0、0))の下に表示され、その高さが画面よりも小さい場合でも上下にスクロールできます。
いくつかのログとブレークポイントを使用すると、読み込みプロセスの開始時に、PagingsCrollViewの境界が問題ないことを判断できました。画面に合うように画像の画像をスケーリングすると変化します。これにより、ViewForZoomingInscrollViewが発生し、ScrollViewDidScrollメソッドが呼び出されます。 PagingScrollViewは、これらの呼び出し中に相殺されています。
オフセットを手動で設定しようとしましたが、プロセスページでそれを行うと、Scrollviewは上下にバウンスできなくなります...
どんな助けも感謝します!
乾杯
PB
解決
Three20には本当に素晴らしい実装があります。派手な機能が必要な場合は、独自の必要性のためにコードを適応させるだけです。
すべてのハードワークはすでに行われています。それでも独自のバージョンを実装したい場合は、少なくとも320コードを見て、達成しようとしていることをどのように行うかを確認してください。
どのように見えるか: http://farm4.static.flickr.com/3432/3378117315_3bf905bdb6_o.jpg
他のヒント
あなたの特定の場合(つまり、 PhotoViewController
に押し付けられています UINavigationController
スタック) - ナビゲーションバーが追加されます contentInset
に PhotoViewController
のスクロールビュー。これはすべてよりよく説明されています ここ と ここ.
つまり、 PhotoViewController
ビューはウィンドウの境界にしっかりと収まらないため、あらゆる方向にスクロールする余地があります。
私はあなたの問題に対する2つの可能な解決策を見つけました。
1-手動で調整する必要があります contentInset
あなたの pagingScrollView
ナビゲーションバーとステータスバーの高さを補正します。これを追加します PhotoViewController
:
- (void)viewDidLoad {
[super viewDidLoad];
CGFloat topOffset = self.navigationController.navigationBar.frame.size.height + [[UIApplication sharedApplication] statusBarFrame].size.height;
pagingScrollView.contentInset = UIEdgeInsetsMake(-topOffset, 0.0, 0.0, 0.0);
}
また
2-スクロールビューのみがあるので contentInset
, 、包みます pagingScrollView
平野で UIView
:
- (void)loadView {
[self setWantsFullScreenLayout:YES];
CGRect pagingScrollViewFrame = [self frameForPagingScrollView];
photoView = [[UIView alloc] initWithFrame:pagingScrollViewFrame];
pagingScrollView = [[UIScrollView alloc] initWithFrame:pagingScrollViewFrame];
// ... configure the pagingScrollView
[photoView addSubview:pagingScrollView];
self.view = photoView;
// ...
}
お役に立てれば!
設定する必要がある主なものは、ビューコントローラーの以下です。コンテンツビューでフラグを自動化する。次のフラグを有効にすると、ビューコントローラーのサイズが画面のフルサイズに拡張されます。 ViewWillappearで以下を実行します。
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self setWantsFullScreenLayout:YES]; // if you want to underlap status
self.navigationController.navigationBar.translucent = YES; // underlap nav controller
self.toolbar.translucent = YES; // if you have a toolbar.
}
詳細については、Appleのドキュメントをご覧ください。
コンテンツビューにフレームバウンドを設定するために何かをしている場合は、上記があなたのためにそれを処理するはずなので、そのコードをすべて削除します。
ビューコントローラーの調整スクロールビューインゼットをストーリーボードからFalseに設定するだけです。