菜鸟教程小白 发表于 2022-12-13 16:45:05

objective-c - iPad 自定义/动态布局


                                            <p><p>我是 iOS 开发的新手。我已经阅读了几个教程并了解了基础知识,但目前我被困在如何继续前进。我计划为基本的家庭自动化(即开关灯、测量温度等)创建一个应用程序。后端都设置好了,所以这只是前端。这是我打算做的:</p>

<ul>
<li>应用的主视图应显示平面图或房屋布局</li>
<li>在此平面图上,您应该能够添加灯光/传感器/等。 - 让我们说对象以保持其通用性</li>
<li>这些对象应该是可拖动的,以便您可以根据它们的实际位置(物理上)将它们排列在平面图上 - 理想情况下,这种拖动模式是可切换的,类似于在主屏幕上重新排列图标</li>
<li>每个对象都应该有一个弹出 View (即设置调光器强度、开关灯等)</li>
</ul>

<p>我知道有很多工作要做,但我真的不知道如何进行设置。目前的替代品:</p>

<ol>
<li>创建一个自定义 UIView 子类,其中包含所有逻辑并在自定义代码中进行绘图,即拖动、弹出框定位等 - 但我觉得我不会真正利用 iOS 框架功能<</li>
<li>将平面图显示为 UIImageView 和每个对象的一个​​ UIButton。这样做的好处是我可以使用 StoryBoard 进行布局和布线(即为弹出框等创建 segues) - 但我根本无法弄清楚如何使用可变数量的按钮来做到这一点(因为我不知道提前有多少按钮)。有没有办法在代码中创建这些按钮?</li>
<li>使用自定义 UITableView。我已经看到了几个示例,即使布局与表格无关(如我的示例中),它们似乎也使用表格 View ,但我还没有找到任何教程更详细地解释这个概念</li>
</ol>

<p>还是我完全走错了路?任何意见表示赞赏。</p>

<p>谢谢
D.</p>

<p>更新:
在对此进行更多研究和思考之后,我认为使用 iOS 6 的方法是使用带有自定义布局的 UICollectionView。一旦我想出了一个完整的解决方案,我会在这里发布。对于较旧的 iOS 版本,我认为使用 Option Nr 会很有希望。 2 - 即在代码中创建每个 UIButton(用于自动化对象,例如灯光)并使用自定义 UIView 子类来对这些按钮进行布局。</p></p>
                                    <br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
                                            <p><p>好的,我认为 UICollectionView 非常适合这种使用场景,我很幸运能够开始使用 iOS 编程,就像它被引入框架一样。下面的示例是一个 UICollectionView,它根据其固有坐标显示其元素。这个例子也可以应用于在 map 上定位对象。我在其他地方找不到任何示例,所以我将在此处发布主要步骤(因为我是初学者,请纠正任何错误)。</p>

<p>首先,我在 XCode 中创建了一个带有一个 View 和 Storyboard的简单项目。我删除了标准 View 并插入了一个 Collection ViewController ,并将我的 UICollectionViewController 子类配置为应该使用的类(在 Storyboard中 Controller 的属性中)。</p>

<p>对于演示,只需将默认 UICollectionViewCell 的背景设置为一种颜色,并将此示例的 Identifier 设置为“AutomationCell”(如果您更改它,请务必调整下面的代码)。</p>

<p>首先,我创建一个简单的对象,其中包含一些属性,这些属性表示应在平面图上显示的对象:</p>

<pre><code>@interface AULYAutomationObject : NSObject

@property NSString *title;
@property CGPoint position;

@end
</code></pre>

<p>然后我需要我自己的委托(delegate)作为标准 UICollectionViewDelegate 的子类,因为我的自定义 UICollectionViewLayout 将无法直接访问 dataSource 对象。因此,我提供了一种方法,可以为我提供对象的位置:</p>

<pre><code>@protocol AULYAutomationObjectLayoutDelegate &lt;UICollectionViewDelegate&gt;

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

@end
</code></pre>

<p>确保在您的 Controller 中实现此协议(protocol),如下所示:</p>

<pre><code>@interface AULYViewController : UICollectionViewController &lt;AULYAutomationObjectLayoutDelegate&gt;
</code></pre>

<p>然后我在 ViewController 子类中实现了标准数据源和委托(delegate)方法以及我的自定义方法:</p>

<pre><code>@interface AULYViewController ()

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

@end

@implementation AULYViewController

- (void)viewDidLoad
{
    ;

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

    // add some objects here...

    self.objects = ;

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

#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 = ;
    // If you have a custom UICollectionViewCell with a label as outlet
    // you could for example then do this:
    // AULYAutomationObject *automationObject = self.objects;
    // cell.label.text = automationObject.title;
    return cell;
}

#pragma mark - AULYAutomationObjectLayoutDelegate

- (CGPoint)getPositionForItemAtIndexPath:(NSIndexPath *)indexPath
{
    AULYAutomationObject *automationObject = self.objects;
    return automationObject.position;
}
</code></pre>

<p>在实际项目中,您可能会从对象模型位置到屏幕上的位置进行一些转换(例如,将 GPS 数据转换为像素),但为了简单起见,这里省略了。</p>

<p>完成之后,我们还需要设置布局。这具有以下属性:</p>

<pre><code>@interface AULYAutomationObjectLayout : UICollectionViewLayout

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

@end
</code></pre>

<p>以及以下实现:</p>

<pre><code>@implementation AULYAutomationObjectLayout

- (void)setDraggedObject:(NSIndexPath *)draggedObject
{
    _draggedObject = draggedObject;
    ;
}

- (void)setDragPosition:(CGPoint)dragPosition
{
    _dragPosition = dragPosition;
    ;
}

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

    if ()
    {
      layoutAttributes.center = self.dragPosition;
      layoutAttributes.transform3D = CATransform3DMakeScale(1.5, 1.5, 1.0);
      layoutAttributes.zIndex = 1;
    }

    return layoutAttributes;
}

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    NSMutableArray *allAttributes = [ initWithCapacity:4];
    for (NSInteger i = 0; i &lt; ; i++)
    {
      NSIndexPath *indexPath = ;
      UICollectionViewLayoutAttributes *layoutAttributes = ;
      ;
    }
    return allAttributes;
}

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

- (CGSize)collectionViewContentSize
{
    return .size;
}

@end
</code></pre>

<p>要在 Storyboard 中设置自定义布局,只需转到 ControllerView 的属性并选择自定义作为布局类型 - 然后选择您的自定义类。</p>

<p>现在要通过长按手势启用拖放支持,只需将以下内容添加到您的 Controller :</p>

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

<p><strong>一个重要提示:</strong>(这至少花费了我一个小时):使用 transform3D 时,您应该确保将 QuartzCore 导入到链接的框架中(在方向设置下方的项目属性中)。否则,您将收到一个 Mach-O 链接器错误,提示找不到 _CATransform3DMakeScale。</p></p>
                                   
                                                <p style="font-size: 20px;">关于objective-c - iPad 自定义/动态布局,我们在Stack Overflow上找到一个类似的问题:
                                                        <a href="https://stackoverflow.com/questions/12728342/" rel="noreferrer noopener nofollow" style="color: red;">
                                                                https://stackoverflow.com/questions/12728342/
                                                        </a>
                                                </p>
                                       
页: [1]
查看完整版本: objective-c - iPad 自定义/动态布局