2

私はiOS開発の初心者です。いくつかのチュートリアルを実行して基本を理解しましたが、現在、さらに先に進む方法に行き詰まっています。基本的なホーム オートメーション (照明の切り替え、温度の測定など) 用のアプリを作成する予定です。バックエンドはすべて設定されているので、これはフロントエンドに関するものです。これは私がやろうとしていることです:

  • アプリのメイン ビューには、間取り図または家のレイアウトが表示されます。
  • このフロア プランでは、ライト/センサーなどを追加できるはずです。-オブジェクトをジェネリックに保つとしましょう
  • これらのオブジェクトは、(物理的に) 実際の位置に合わせてフロア プランに配置できるようにドラッグ可能である必要があります。理想的には、このドラッグ モードは、ホーム画面のアイコンを再配置するのと同じように切り替え可能です。
  • 各オブジェクトにはポップオーバー ビューが必要です (つまり、ディマーの強度を設定したり、ライトを切り替えたりするため)。

やるべきことがたくさんあることは知っていますが、これを設定する方法が本当にわかりません。現在の代替案:

  1. カスタムコードでの描画、つまりドラッグ、ポップオーバーの配置などを行うすべてのロジックを含むカスタム UIView サブクラスを作成します。
  2. フロア プランを UIImageView として表示し、オブジェクトごとに 1 つの UIButton を表示します。これには、StoryBoard を使用してレイアウトと配線を行うことができるという利点があります (つまり、ポップオーバーのセグエを作成するなど) - しかし、可変数のボタンでこれを行う方法がわかりません (わからないため)ボタンの数を事前に確認してください)。これらのボタンをコードで作成する方法はありますか?
  3. カスタム UITableView を使用します。レイアウトがテーブルとは関係なくてもテーブルビューを使用しているように見える例をいくつか見ましたが (私の例のように)、この概念をより詳細に説明するチュートリアルは見つかりませんでした

それとも、私は完全に間違った方向に進んでいますか? どんな入力でも大歓迎です。

ありがとう。

更新: これについてさらに調査して考えた結果、iOS 6 を使用する方法は、カスタム レイアウトで UICollectionView を使用することだと思います。完全な解決策を見つけたら、ここに投稿します。古い iOS バージョンの場合、Option Nr を使用することが有望だと思います。2 - つまり、コードで各 UIButton (ライトなどのオートメーション オブジェクト用) を作成し、これらのボタンのレイアウトを行うカスタム UIView サブクラスを用意します。

4

1 に答える 1

3

わかりました UICollectionView はこの使用シナリオに最適だと思います。フレームワークに導入されたのと同じように iOS プログラミングを開始できたことは幸運です。次の例は、固有の座標に従って要素を表示する UICollectionView です。この例は、マップ上のオブジェクトの配置にも適用できます。他の場所で例を見つけることができなかったので、ここに主な手順を投稿します (私は初心者なので、間違いを修正してください)。

まず、XCode で 1 つのビューとストーリーボードを含む単純なプロジェクトを作成しました。標準ビューを削除し、代わりに Collection View Controller を挿入し、UICollectionViewController サブクラスを (ストーリーボードのコントローラーのプロパティで) 使用するクラスとして構成しました。

デモでは、デフォルトの UICollectionViewCell の背景を色に設定し、この例の識別子を "AutomationCell" に設定します (変更する場合は、必ず以下のコードを調整してください)。

最初に、フロア プランに表示するオブジェクトを表すいくつかのプロパティを持つ単純なオブジェクトを作成します。

@interface AULYAutomationObject : NSObject

@property NSString *title;
@property CGPoint position;

@end

次に、カスタム UICollectionViewLayout は dataSource オブジェクトに直接アクセスできないため、標準 UICollectionViewDelegate のサブクラスとして独自のデリゲートが必要です。したがって、オブジェクトの位置を取得するメソッドを提供します。

@protocol AULYAutomationObjectLayoutDelegate <UICollectionViewDelegate>

- (CGPoint)getPositionForItemAtIndexPath:(NSIndexPath *)indexPath;

@end

このプロトコルをコントローラーに次のように実装してください。

@interface AULYViewController : UICollectionViewController <AULYAutomationObjectLayoutDelegate>

次に、標準のデータソース メソッドとデリゲート メソッドを、ビュー コントローラー サブクラスのカスタム メソッドと共に実装しました。

@interface AULYViewController ()

@property NSArray *objects;
@property (strong, nonatomic) IBOutlet UICollectionView *collectionView;

@end

@implementation AULYViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Set up the data source
    NSMutableArray *automationObjects = [[NSMutableArray alloc] initWithCapacity:10];

    // add some objects here...

    self.objects = [automationObjects copy];

    UILongPressGestureRecognizer *longPressRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];
    [self.collectionView addGestureRecognizer:longPressRecognizer];
}

#pragma mark - UICollectionViewController 
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
    return 1;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return self.objects.count;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    AULYAutomationObjectViewCell *cell = [collectionView     dequeueReusableCellWithReuseIdentifier:@"AutomationCell" forIndexPath:indexPath];
    // If you have a custom UICollectionViewCell with a label as outlet 
    // you could for example then do this:
    // AULYAutomationObject *automationObject = self.objects[indexPath.row];
    // cell.label.text = automationObject.title;
    return cell;
}

#pragma mark - AULYAutomationObjectLayoutDelegate

- (CGPoint)getPositionForItemAtIndexPath:(NSIndexPath *)indexPath
{
    AULYAutomationObject *automationObject = self.objects[indexPath.item];
    return automationObject.position;
}

実際のプロジェクトでは、おそらくオブジェクト モデルの位置から画面上の位置への変換 (たとえば、GPS データからピクセルへ) を行うことになりますが、ここでは簡単にするために省略しています。

それを行った後、レイアウトを設定する必要があります。これには次のプロパティがあります。

@interface AULYAutomationObjectLayout : UICollectionViewLayout

@property (nonatomic, strong) NSIndexPath *draggedObject;
@property (nonatomic) CGPoint dragPosition;

@end

そして、次の実装:

@implementation AULYAutomationObjectLayout

- (void)setDraggedObject:(NSIndexPath *)draggedObject
{
    _draggedObject = draggedObject;
    [self invalidateLayout];
}

- (void)setDragPosition:(CGPoint)dragPosition
{
    _dragPosition = dragPosition;
    [self invalidateLayout];
}

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewLayoutAttributes *layoutAttributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    id viewDelegate = self.collectionView.delegate;
    if ([viewDelegate respondsToSelector:@selector(getPositionForItemAtIndexPath:)])
    {
        CGPoint itemPosition = [viewDelegate getPositionForItemAtIndexPath:indexPath];
        layoutAttributes.center = itemPosition;
        layoutAttributes.size = CGSizeMake(ITEM_SIZE, ITEM_SIZE);
    }

    if ([self.draggedObject isEqual:indexPath])
    {
        layoutAttributes.center = self.dragPosition;
        layoutAttributes.transform3D = CATransform3DMakeScale(1.5, 1.5, 1.0);
        layoutAttributes.zIndex = 1;
    }

    return layoutAttributes;
}

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    NSMutableArray *allAttributes = [[NSMutableArray alloc] initWithCapacity:4];
    for (NSInteger i = 0; i < [self.collectionView numberOfItemsInSection:0]; i++)
    {
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
        UICollectionViewLayoutAttributes *layoutAttributes = [self layoutAttributesForItemAtIndexPath:indexPath];
        [allAttributes addObject:layoutAttributes];
    }
    return allAttributes;
}

- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
    return YES;
}

- (CGSize)collectionViewContentSize
{
    return [self.collectionView frame].size;
}

@end

ストーリーボードでカスタム レイアウトを設定するには、コントローラー ビューのプロパティに移動し、レイアウト タイプとしてカスタムを選択してから、カスタム クラスを選択します。

長押しジェスチャでドラッグ アンド ドロップのサポートを有効にするには、コントローラーに以下を追加するだけです。

- (void)handleTapGesture:(UITapGestureRecognizer *)sender
{
    AULYAutomationObjectLayout *automationLayout = (AULYAutomationObjectLayout *)self.collectionView.collectionViewLayout;
    if (sender.state == UIGestureRecognizerStateBegan)
    {
        CGPoint initialPinchPoint = [sender locationInView:self.collectionView];
        NSIndexPath* tappedCellPath = [self.collectionView indexPathForItemAtPoint:initialPinchPoint];
        [self.collectionView performBatchUpdates:^{
            automationLayout.draggedObject = tappedCellPath;
            automationLayout.dragPosition = initialPinchPoint;
        } completion:nil];
    }
    else if (sender.state == UIGestureRecognizerStateChanged)
    {
        automationLayout.dragPosition = [sender locationInView:self.collectionView];
    }
    else if (sender.state == UIGestureRecognizerStateEnded)
    {
        AULYAutomationObject *automationObject = self.objects[automationLayout.draggedObject.item];
        automationObject.position = [sender locationInView:self.collectionView];
        [self.collectionView performBatchUpdates:^{
            automationLayout.draggedObject = nil;
            automationLayout.dragPosition = CGPointMake(0.0, 0.0);
        } completion:nil];
    }
}

1 つの重要な注意事項: (これには少なくとも 1 時間かかりました): transform3D を使用する場合は、QuartzCore をリンクされたフレームワークにインポートする必要があります (方向設定の下のプロジェクト プロパティで)。そうしないと、_CATransform3DMakeScale が見つからないという Mach-O リンカー エラーが発生します。

于 2012-10-10T14:40:54.787 に答える