UIView动画代码应该放在哪里根据VIPER设计模式?
它应该在视图中还是在演示者中?
注意:
我有一个CustomView,我想在触摸屏幕后移动.
CustomView将添加到ViewController中的Screen中
最佳答案 你应该把它放在[R]外面.它在 this article中有详细描述:
Since the Presenter contains the logic to react to user inputs, it is
the Presenter that knows when to navigate to another screen, and which
screen to navigate to. Meanwhile, the wireframe knows how to navigate.
So, the Presenter will use the wireframe to perform the navigation.
Together, they describe a route from one screen to the next.The wireframe is also an obvious place to handle navigation transition
animations.
请注意,他们将路由器称为线框.
更新(根据问题和评论的更新回答更正)
我会根据these articles给出我的意见.
让我们考虑两种情况:简单和复杂.在简单的情况下,任务只是将视图的位置更改为具有动画的预定义位置(即更改状态).在更复杂的情况下,任务是根据触摸坐标改变自定义视图的位置.
看看这个简单的案例.你有一个包含自定义视图的[V] iewController. ViewController采用ViperView协议:
@protocol VIPERView
- (void)changeCustomViewState;
@end
@interface ViewController : UIViewController<VIPERView>
@end
在实现中,我们有这样的事情:
@implementation ViewController {
BOOL _isInitialState;
IBOutlet UIView *_customView;
}
- (void)changeCustomViewState
{
_isInitialState = !_isInitialState;
[self changeCustomViewPositionAnimated:YES];
}
- (void)changeCustomViewPositionAnimated:(BOOL)animated
{
void(^performChange)() = ^() {
if (_isInitialState)
_customView.center = CGPointMake(50, 50);
else
_customView.center = CGPointMake(250, 250);
};
if (animated)
{
[UIView animateWithDuration:[CATransaction animationDuration] animations:^{
performChange();
}];
}
else
{
performChange();
}
}
根据VIPER的视图责任是“向用户显示信息”和“检测用户交互”,除了通知[P] resenter关于此事件之外,不允许在触摸后做出决定.演示者依次制作决定做什么和做什么
[self.viperView changeCustomViewState];
因此,执行位于[V] iew但[P] resenter中的动画的实际代码会触发其执行(因为它的职责是“告诉视图显示什么”和“处理事件”).
定义自定义视图的位置是视图布局的jsut部分.所以它是配置的一部分.演示者只是以动画方式转动它.
在更复杂的情况下,我们将考虑根据触摸位置更改自定义视图的位置.
我们的任务是在触摸后改变视图的位置,使其保持在屏幕上.例如,如果视图位于屏幕的左下角,则触摸不应将其移动到屏幕边界下方或屏幕左侧后方.它应该在三个自由角之一中移动视图.
在这种情况下,我们的视图协议将如下所示:
@protocol VIPERView
// @param - related position to the screen bounds in range (0;1)
- (void)changeCustomViewRelatedPosition:(CGPoint)point animated:(BOOL)animated;
@end
并在实施中
@implementation ViewController {
IBOutlet UIView *_customView;
}
- (void)changeCustomViewRelatedPosition:(CGPoint)point animated:(BOOL)animated
{
CGPoint thisCoordinateSpacePoint = // translate ‘point’ to screen’s coordinate space ;
void(^performChange)() = ^() {
_customView.center = thisCoordinateSpacePoint;
};
if (animated)
{
[UIView animateWithDuration:[CATransaction animationDuration] animations:^{
performChange();
}];
}
else
{
performChange();
}
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
CGPoint point = //determine location
[self.viperPresenter userDidTouchViewWithPosition:point];
}
@end
对于[P] resenter,我们需要在这种情况下定义协议:
@protocol VIPERPresenter
- (void)userDidTouchViewWithPosition:(CGPoint)point;
@end
当用户触摸屏幕时,视图会调用演示者通知某些事件:
[self.viperPresenter userDidTouchViewWithPosition:point];
正如文章所述:
The presenter is notified of events by the view and part of its job is
to handle those events accordingly. This usually means asking the
interactor to retrieve some bit of information or carry out some task.
在我们的案例中,app需要确定应该移动视图的坐标.该算法可以封装并且可以互换.所以我们可以从不同的地方检索这个算法:数据库,服务器等.为了完成这个任务,我们使用[I] nteractor:
// in Presenter class
[self.viperInteractor handleCoordinates:(CGPoint)point];
然后[I] nteractor要求DataManager使用[E]中的算法以某种方式将这些坐标映射到新的坐标(如果它在右上角或左上角移动)并通过新坐标通知[P] resenter(角视图)应该移动).最后,Presenter执行:
[self.viperView changeCustomViewRelatedPosition:newPosition];
同样,动画代码作为布局的一部分放在[V]内部.但决定(确切参数)由其他组件定义(Presenter,Interactor,Entity)