だいたい47度

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

PageTop

無限にスクロールできるUIScrollView

結構簡単に作れました。

ページャブルなUIScrollViewに3ページだけスペースを用意し、ページがめくれると順次ページを繰り上げる。それを繰り返すことで無限にスクロールできるようにしました。

新しいページはEndlessScrollViewDelegateプロトコルを作成し、- (UIView *)viewOfPage:(int)pageでページ数を指定して供給します。ページの左右端を指定するときは、viewOfPageでnilを返してあげると、普通にスクロールしてbounceするようになります。
endlessScroll

//EndlessScrollViewDelegate.h
@protocol EndlessScrollViewDelegate
- (UIView *)viewOfPage:(int)page;
@end

//EndlessScrollView.h
@interface EndlessScrollView : UIScrollView

@property (nonatomic, strong) UIView *pageView1;
@property (nonatomic, strong) UIView *pageView2;
@property (nonatomic, strong) UIView *pageView3;

@property (nonatomic, weak) id endscrollDelegate;

- (void)createFirst3Pages;

@end

//EndlessScrollView.m
#import "EndlessScrollView.h"

@implementation EndlessScrollView
{
  int _centerPageNum;
  BOOL _isLoadableScrollView;
}

- (id)initWithFrame:(CGRect)frame
{
  self = [super initWithFrame:frame];
  if (self) {
   self.contentSize = CGSizeMake(frame.size.width * 3, frame.size.height);
   self.pagingEnabled = YES;
   self.showsHorizontalScrollIndicator = NO;
   self.scrollsToTop = NO; // ステータスバーのタップによるトップ移動禁止
   self.delegate = self;
  }
  return self;
}

- (void)createFirst3Pages
{
  self.pageView1 = [self.endscrollDelegate viewOfPage:1];
  self.pageView2 = [self.endscrollDelegate viewOfPage:2];
  self.pageView3 = [self.endscrollDelegate viewOfPage:3];
  self.pageView1.frame = [self correctRectOfPageView:1];
  self.pageView2.frame = [self correctRectOfPageView:2];
  self.pageView3.frame = [self correctRectOfPageView:3];
  [self addSubview:self.pageView1];
  [self addSubview:self.pageView2];
  [self addSubview:self.pageView3];

  if (self.pageView2 == nil) {
   _isLoadableScrollView = NO;
   self.contentSize = CGSizeMake(self.frame.size.width * 1 + 1,//bounceさせる1
    self.frame.size.height);
  } else if (self.pageView3 == nil) {
   _isLoadableScrollView = NO;
   self.contentSize = CGSizeMake(self.frame.size.width * 2, self.frame.size.height);
  }else {
   _isLoadableScrollView = YES;
  }

  _centerPageNum = 2;
}

- (CGRect)correctRectOfPageView:(int)pageViewNum
{
  float x = self.frame.size.width * (pageViewNum - 1);
  return CGRectMake(x, 0, self.frame.size.width, self.frame.size.height);
}

#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
  if (_isLoadableScrollView == NO) {
   return;
  }

  CGFloat position = scrollView.contentOffset.x / scrollView.bounds.size.width;
  if (position >= 2.0f) {
   int nextPage = _centerPageNum + 1;
   UIView *nextView = [self.endscrollDelegate viewOfPage:nextPage + 1];

   if (nextView) {
    [self addSubview:nextView];

    nextView.frame = self.pageView3.frame;
    self.pageView3.frame = self.pageView2.frame;
    self.pageView2.frame = self.pageView1.frame;

    [self.pageView1 removeFromSuperview];
    self.pageView1 = self.pageView2;
    self.pageView2 = self.pageView3;
    self.pageView3 = nextView;
    self.contentOffset = CGPointMake(self.bounds.size.width, 0);

    _centerPageNum = nextPage;
   }
  } else if (position <= 0.0) {
   int nextPage = _centerPageNum - 1;
   UIView *nextView = [self.endscrollDelegate viewOfPage:nextPage - 1];

   if (nextView) {
    [self addSubview:nextView];

    nextView.frame = self.pageView1.frame;
    self.pageView1.frame = self.pageView2.frame;
    self.pageView2.frame = self.pageView3.frame;

    [self.pageView3 removeFromSuperview];
    self.pageView3 = self.pageView2;
    self.pageView2 = self.pageView1;
    self.pageView1 = nextView;
    self.contentOffset = CGPointMake(self.bounds.size.width, 0);

    _centerPageNum = nextPage;
   }
  }
}

@end


- (void)scrollViewDidScroll:(UIScrollView *)scrollViewで制御しちゃっているので、- (UIView *)viewOfPage:(int)pageが呼び出された時にnilを返す処理が重いときついです。didEnd系はページを複数枚一気にめくろうとするときに対処出来ません。頑張ればいろいろできるけど、とりあえずこれで目的は達成。

使う方は、普通にEndlessScrollViewをaddしてあげてcreateFirst3Pagesを呼び出すだけでOK。もちろんEndlessScrollViewDelegateのviewOfPageの実装も忘れずに。

スポンサーサイト

PageTop

iOSモダルパネルライブラリUAModalPanelのよくやる使い方

iOS開発でモダルを使いたいとき、UAModalPanelが便利です。

基本的にはUAModalPanelの子クラスを作り、contentViewプロパティに描画したいViewをaddしていけばOK。showFromPointを実行すればモダルがそのポイントから出現します。githubの他、cocoapodsからもDLできます。iOSオープンソースライブラリ徹底活用にも出ています。

ただ、ちょいちょい癖があって使い方がわからないことがあるので、よく使う部分をメモします。

1) Xibで扱いたい。
InterfaceBuilderでパネルの中身を作りたい場合。MyModalPanelというクラスを作って、同名のxibファイルがあるとします。xibではFile's OwnerをMyModalPanelとし、MyModalPanel.hで定義したbaseViewプロパティがObjectsの大本Viewになるようにしておきます。

//MyModalPanel.m
- (id)initWithFrame:(CGRect)frame
{
   if ((self = [super initWithFrame:frame])) {
       [[NSBundle mainBundle] loadNibNamed:@"MyModalPanel" owner:self options:nil];
      float topMargin = 200;
      float bottomMargin = frame.size.height - topMargin - _baseView.frame.size.height;
      float leftMargin = (frame.size.width - _baseView.frame.size.width) / 2;

      self.shouldBounce = NO;
      self.margin = UIEdgeInsetsMake(topMargin, leftMargin, bottomMargin, leftMargin);
      self.padding = UIEdgeInsetsMake(0, 0, 0, 0);
      self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
      self.cornerRadius = 0;

      [self.contentView addSubview:_baseView];
      [_baseView setFrame:self.contentView.frame];
   }
}


topMarginを適当に調整すれば、良い感じの位置に表示させてくれます。paddingはなしにするのが僕は好き。initで指定しなくても、showFromPointを実行する前にself.marginを変えてあげれば任意の場所にパネルを描画できます。

2) 左上のバツボタンを消したい。
左上にバツボタンが出てしまいますが、アプリとあまりにも感じが違う場合は消してしまいたいです。

このボタンはcloseButtonプロパティで指定されるボタンなので、単純にそれを消せばOK。他に消すボタンを作った場合は、このcloseButtonの消す処理を呼んであげるのが良いです。パネルをアニメーションで消したりとかの処理をきちんとやってくれるので。

//MyModalPanel.mのinit
   [self.closeButton setHidden:YES];

//MyModalPanel.m
- (IBAction)myCloseButtonTapped:(id)sender
{
   [self.closeButton sendActionsForControlEvents:UIControlEventTouchUpInside];
}



3) パネルの大きさを動的に変えたい。
パネル内のボタンを押したら、パネルをニョっと拡大させたいことがあります。そんなときは、パネルの中身の拡大&marginの修正&再描画が必要です。

//tapSomeButton
[UIView animateWithDuration:0.2f
   animations:^{
      self.contentView.frame = //お好みのサイズ
   }
   completion:^(BOOL finished){
      self.margin = //対応したエッジ
      [self layoutSubviews];//忘れずに
   }];


marginの修正をanimationの中で行うと、ちょっと描画が変になることがあるので、completionの中でやっています。見た目上はcompletionの中身がなくても問題ないですが、拡張した領域でのタップ感知などのためにはmarginの修正が必要です。やっておきましょう。

便利なライブラリがあると開発がとても楽ですね。

PageTop
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。