エンジニアリングにはほど遠い

iPhoneアプリとかサイトとかをつくっていくブログです。

iOS addSubViewのときに隅とか真ん中に楽に置けるカテゴリ

ただまんま書いただけなのですが、作っておくととても便利でした。

UIView+adjustSubView.h

#import <UIKit/UIKit.h>

typedef enum {
    UIViewAdjustSubViewLeftTop,
    UIViewAdjustSubViewLeftCenter,
    UIViewAdjustSubViewLeftButtom,
    UIViewAdjustSubViewCenterTop,
    UIViewAdjustSubViewCenter,
    UIViewAdjustSubViewCenterButtom,
    UIViewAdjustSubViewRightTop,
    UIViewAdjustSubViewRightCenter,
    UIViewAdjustSubViewRightButtom,
} UIViewAdjustSubView;

@interface UIView (adjustSubView)

- (void)addSubview:(UIView *)view location:(UIViewAdjustSubView)location margin:(CGFloat)margin;
- (void)addSubview:(UIView *)view location:(UIViewAdjustSubView)location marginX:(CGFloat)marginX marginY:(CGFloat)marginY;

@end

UIView+adjustSubView.m

#import "UIView+adjustSubView.h"

@implementation UIView (adjustSubView)

- (void)addSubview:(UIView *)view location:(UIViewAdjustSubView)location margin:(CGFloat)margin
{
    [self addSubview:view location:location marginX:margin marginY:margin];
}

- (void)addSubview:(UIView *)view location:(UIViewAdjustSubView)location marginX:(CGFloat)marginX marginY:(CGFloat)marginY
{
    CGFloat x, y;
    
    switch (location) {
        case UIViewAdjustSubViewLeftTop:
            x = marginX;
            y = marginY;
            break;
        case UIViewAdjustSubViewLeftCenter:
            x = marginX;
            y = ( self.frame.size.height - view.frame.size.height) / 2;
            break;
        case UIViewAdjustSubViewLeftButtom:
            x = marginX;
            y = ( self.frame.size.height - view.frame.size.height - marginY );
            break;
        case UIViewAdjustSubViewCenterTop:
            x = ( self.frame.size.width - view.frame.size.width) / 2;
            y = marginY;
            break;
        case UIViewAdjustSubViewCenter:
            x = ( self.frame.size.width - view.frame.size.width) / 2;
            y = ( self.frame.size.height - view.frame.size.height) / 2;
            break;
        case UIViewAdjustSubViewCenterButtom:
            x = ( self.frame.size.width - view.frame.size.width) / 2;
            y = ( self.frame.size.height - view.frame.size.height - marginY );
            break;
        case UIViewAdjustSubViewRightTop:
            x = ( self.frame.size.width - view.frame.size.width - marginX );
            y = marginY;
            break;
        case UIViewAdjustSubViewRightCenter:
            x = ( self.frame.size.width - view.frame.size.width - marginX );
            y = ( self.frame.size.height - view.frame.size.height ) / 2;
            break;
        case UIViewAdjustSubViewRightButtom:
            x = ( self.frame.size.width - view.frame.size.width - marginX );
            y = ( self.frame.size.height - view.frame.size.height - marginY );
            break;
        default:
            break;
    }
    
    view.frame = CGRectMake(x, y, view.frame.size.width, view.frame.size.height);

    [self addSubview:view];
}

@end

使い方

(右に置くときは縦横の間隔40px指定、それ以外は縦60px横20px指定)

    // サイズが40pxの正方形のsubViewを作る
    UIView *view1 = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 40, 40)];
    view1.backgroundColor = [UIColor blueColor];
    UIView *view2 = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 40, 40)];
    view2.backgroundColor = [UIColor blueColor];
    // 省略...
    
    [self.view addSubview:view1 location:UIViewAdjustSubViewCenter marginX:20 marginY:60];
    [self.view addSubview:view2 location:UIViewAdjustSubViewCenterButtom marginX:20 marginY:60];
    [self.view addSubview:view3 location:UIViewAdjustSubViewCenterTop marginX:20 marginY:60];
    [self.view addSubview:view4 location:UIViewAdjustSubViewLeftButtom marginX:20 marginY:60];
    [self.view addSubview:view5 location:UIViewAdjustSubViewLeftCenter marginX:20 marginY:60];
    [self.view addSubview:view6 location:UIViewAdjustSubViewLeftTop marginX:20 marginY:60];
    
    [self.view addSubview:view7 location:UIViewAdjustSubViewRightButtom margin:40];
    [self.view addSubview:view8 location:UIViewAdjustSubViewRightCenter margin:40];
    [self.view addSubview:view9 location:UIViewAdjustSubViewRightTop margin:40];

f:id:J_ogawa:20140406233815p:plain

単純ですが結構使ってます。
こういう自分パーツをいっぱい作っておけばどんどん効率化できそうですね。

あと、QuickDialogのカスタマイズとかできるようになればかなり捗りそうなんで、今の課題ですね。

iOS 文字数で縦幅が変化するラベルを持つビューを作るカテゴリ

よく使う機能なのでカテゴリ化して作りました。

最後ceilしてるのはこちらを参考にさせていただきました。

引数のtextはNSStringとNSAttributedStringに対応してます。

※デカすぎるものを作ると落ちるので注意して下さい。

gist9976186

使うときはこういう感じで。

    NSString *str = @"sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss";
    
    NSMutableAttributedString *attrStr = [[NSMutableAttributedString alloc] initWithString:@"SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS"];
    [attrStr addAttribute:NSFontAttributeName
                    value:[UIFont systemFontOfSize:26.0]
                    range:NSMakeRange(24, 40)];
    
    UIView *view1 = [[UIView alloc]initWithFrame:CGRectMake(0, 20, 320, 0) text:str padding:5 maxHeight:1000 templateLabel:nil];
    view1.backgroundColor = [UIColor greenColor];
    [self.view addSubview:view1];
    
    UIView *view2 = [[UIView alloc]initWithFrame:CGRectMake(0, 20 + view1.frame.size.height + 50, 320, 0) text:attrStr padding:5 maxHeight:1000 templateLabel:nil];
    view2.backgroundColor = [UIColor purpleColor];
    [self.view addSubview:view2];

f:id:J_ogawa:20140405004919p:plain

結構便利です。

ググりまくれるスクリプトを書いた

pod list とか brew cask search とかの内容をいっぱい検索したいなぁと思い。
(open url でブラウザ起動できる必要あり)

google search each arg keywords. example: pod lis ...

(10件以上のときは確認メッセージが出ます)

使い方

pod list | grep -i web | awk '{print $1}' | xargs ggr

ハマったポイントを。

  • echo -n なのに改行しない機能が無視されて、 -n がよけいに出力される
    • #!/bin/sh と書いてたのが原因でした。「入門UNIXシェルプログラミング」ではこう書くのがいいよという事が書かれていたけど、これはこれでいろいろと内部のエイリアス的なものが変わったりするのだろうか。
  • read で入力待ちにならない現象発生
    • 入力をパイプで送ると、標準入力がパイプからになって端末じゃなくなるからとのこと。</dev/tty で解決した
  • 実行できれば言語とかは何でもいい
    • 1行目の指定がミソで、ここで対応できるものならどんな言語でもいいと。知らなかったので目から鱗が落ちました。

シェルスクリプトを書いたのはほぼ初めてで、メチャクチャ楽しかった。

キーボードでUIパーツが隠れるのをUIScrollViewにて上にスクロールして回避

昔からなされている事だとは思いますが、今日初めてその問題に突き当たったので。

Appleの公式のやり方だとなんか動かなかったので少しだけ別のやり方で。

考え方として、見せたいUIパーツの下の部分がキーボードに隠れた時に、隠れた分だけ上に上げる、ということでしょう。
で、このUIパーツの下の部分なんですが、ややこしいので絶対座標で考えようと思います。

で、絶対座標についてはこちらを参考にさせていただきました。この方法だと、status barがあろうと、navigation barがあろうとなかろうと、画面の一番上からの位置が出せました。

これをpartsAbsBottomPointとしました。

f:id:J_ogawa:20140403005039p:plain

位置関係的にこういう感じなので(汚ねえ・・)、

partsAbsBottomPoint.y > (window height) - (keyboard height)

このときに隠れるということになります。隠れる分は partsAbsBottomPoint.y - (window.height - keyboard.height) 。

コード的にこういう感じでしょうか。

float overlapValue = partsAbsBottomPoint.y - (window.height - keyboard.height)
if (overlapValue > 0) {
  overlapValue分だけスライドさせる
}

その結果

- (CGPoint)absPoint:(UIView *)view
{
    CGPoint ret = CGPointMake(view.frame.origin.x, view.frame.origin.y);
    if ([view superview] != nil)
    {
        CGPoint addPoint = [self absPoint:[view superview]];
        ret = CGPointMake(ret.x + addPoint.x, ret.y + addPoint.y);
    }
    return ret;
}

// Call this method somewhere in your view controller setup code.
- (void)registerForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWasShown:)
                                                 name:UIKeyboardDidShowNotification object:nil];
    
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillBeHidden:)
                                                 name:UIKeyboardWillHideNotification object:nil];
}

// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)notification
{
    CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
    //UIKeyboardFrameEndUserInfoKey: better when conversion candidates appear
  
    CGPoint partsAbsOrigin = [self absPoint:_showParts];
    CGPoint partsAbsBottomPoint = (CGPoint){ partsAbsOrigin.x, partsAbsOrigin.y + _showParts.frame.size.height };
    
    float overlapValue = partsAbsBottomPoint.y - ([[UIApplication sharedApplication] keyWindow].frame.size.height - keyboardSize.height);
    
    if (overlapValue > 0){
        CGPoint scrollPoint = CGPointMake(0.0, overlapValue);
        [_rootScrollView setContentOffset:scrollPoint animated:YES];
    }
}

// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    [_rootScrollView setContentOffset:CGPointZero animated:YES];
}

_showPartsには見せたいパーツのインスタンスを入れる。

#pragma mark UITextViewDelegate

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    self.showParts = textField;
}

- (void)textFieldDidEndEditing:(UITextField *)textField
{
    self.showParts = nil;
}

github
サブクラスにして使ってみてます。

しかしまだTableView上のフォームはうまく対応できていない。

UIScrollViewにviewを追加していけるカテゴリ

作ってみたらかなり重宝してます。

かなりまんま書いてて賢くないソースだし、イレギュラーな使い方とか考慮していないのですが。

add content to UIScrollView, auto calc scrollView' ...

Vimがステキ

去年の8月からVimを使い始めてようやく慣れてきた。

しかしiOSを作るときにはXcodeを使ってて、まあXcodeも好きなのだけど、Vimっぽい動きをしたいときが多くなってきた。特にデータを切り貼りしたりするときに行単位のRecoding機能を使いたくなる。

RubyのハッシュとかJSONとかをNSDictionaryのリテラルに書き直すのもVimだと作業自体が楽しい。

まだ考えながらやってる感が出まくっている...w

あと、動画をgif化して貼るみたいなことをやってみたかったのだけどできなくて、とりあえず動画をまんま貼ってみました。