2012-10-04 59 views
2

我是iOS开发的新手。我已经通过了几个教程并了解基础知识,但是目前我陷入了如何进一步发展的过程中。我打算创建一个基本的家庭自动化应用程序(即开关灯,测量温度等)。后端全部设置好了,所以这只是前端。这就是我打算做的事:iPad定制/动态布局

  • 应用程序应显示你应该能够增加灯/传感器/等平面图或房子
  • 布局这层楼计划的主要观点。 - 让对象保持其通用性
  • 这些对象应该是可拖动的,以便您可以根据它们的实际位置(物理上)将它们排列在平面图上 - 理想情况下,此拖动模式类似于重新排列主屏幕上的图标
  • 每个对象应具有酥料饼的视图(即设置调光强度,开关灯等)

我知道有很多工作要做,但我真的不知道如何设置这起来了。当前选择:

  1. 创建一个包含所有逻辑的自定义UIView子类的做图中的自定义代码,即拖动时,酥料饼的定位等等 - 但我不得不说我不会真的被利用的感觉iOS框架功能
  2. 将平面图显示为每个对象的UIImageView和一个UIButton。这有一个好处,我可以使用StoryBoard进行布局和布线(即创建弹出窗口等) - 但我根本无法弄清楚如何用可变数量的按钮来做到这一点(因为我不知道预先有多少个按钮)。有什么方法可以在代码中创建这些按钮吗?
  3. 使用自定义的UITableView。我已经看到了几个例子,他们似乎使用表格视图即使布局无关(在我的例子一样)使用表格要做,但我还没有发现,更详细地解释这一概念的任何教程

还是我完全在错误的轨道上?任何输入赞赏。

感谢 D.

UPDATE: 一些调查研究后,认为这个我觉得去与iOS 6的方法是使用一个UICollectionView带有自定义布局。一旦我想出了一个完整的解决方案,我会在这里发布。对于较老的iOS版本,我认为它会很有希望与Option Nr一起使用。 2 - 即在代码中创建每个UIButton(用于自动化对象,例如灯光)并具有自定义UIView子类来执行这些按钮的布局。

回答

3

好的我认为UICollectionView是这种使用场景的理想选择,我很幸运的开始使用iOS编程,就像它被引入框架一样。以下示例是一个UICollectionView,根据其固有坐标显示其元素。这个例子也可以应用于在地图上定位对象。我在其他地方找不到任何示例,因此我会在此处发布主要步骤(因为我是初学者,请更正任何错误)。

首先,我创建了一个简单的项目,其中包含一个视图和XCode中的故事板。我删除了标准视图,并插入了一个Collection View Controller,并将我的UICollectionViewController子类配置为应该使用的类(在storyboard中的控制器的属性中)。

对于该示例,只需将默认UICollectionViewCell的背景设置为一种颜色,并将标识符设置为“AutomationCell”(如果更改它,请务必调整下面的代码)。

首先,我创建一个表示要在楼层平面图上显示的对象的某些属性的简单对象:

@interface AULYAutomationObject : NSObject 

@property NSString *title; 
@property CGPoint position; 

@end 

然后,我需要我自己的委托作为子类的标准UICollectionViewDelegate因为我的自定义UICollectionViewLayout会不能直接访问dataSource对象。因此,我提供给我的物体的位置的方法:

@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小时):当使用transform3D你应该确保将QuartzCore导入你的链接框架(在方向设置下的项目属性中)。否则,你会得到一个Mach-O链接器错误,说_CATransform3DMakeScale找不到。