ios - sidemenu - SWRevealViewController cierra la vista posterior al tocar la vista frontal
slide out menu swift 4 (9)
Estoy usando SWRevealViewController
para implementar un menú de navegación lateral en mi aplicación. Me gustaría hacerlo para que la vista frontal no pueda interactuar cuando se abre la vista trasera, excepto que cuando el usuario toca la vista frontal, la vista trasera se cerrará y la vista frontal se podrá interactuar nuevamente. Tengo estos dos métodos de delegado SWRevealViewController
que actualmente eliminan la interacción de la vista frontal.
- (void)revealController:(SWRevealViewController *)revealController willMoveToPosition: (FrontViewPosition)position {
if(position == FrontViewPositionLeft) {
self.view.userInteractionEnabled = YES;
} else {
self.view.userInteractionEnabled = NO;
}
}
- (void)revealController:(SWRevealViewController *)revealController didMoveToPosition: (FrontViewPosition)position {
if(position == FrontViewPositionLeft) {
self.view.userInteractionEnabled = YES;
} else {
self.view.userInteractionEnabled = NO;
}
}
Sin embargo, esto no hace que la vista trasera se cierre cuando se toca la vista frontal. ¡Cualquier ayuda sería muy apreciada, gracias!
- Subclase de
SWRevealViewController
. - Implementar
revealController:willMoveToPosition:
deSWRevealViewControllerDelegate
. - Configure la vista de pantalla completa en el controlador de vista frontal para anular todos los toques.
- Añadir toque gesto reconocedor para ocultar el menú.
Muestra con buena animación:
- (void)revealController:(SWRevealViewController *)revealController willMoveToPosition:(FrontViewPosition)position;
{
static NSInteger tagLockView = 4207868622;
if (revealController.frontViewPosition == FrontViewPositionRight) {
UIView *lock = [self.frontViewController.view viewWithTag:tagLockView];
[UIView animateWithDuration:0.25 animations:^{
lock.alpha = 0;
} completion:^(BOOL finished) {
[lock removeFromSuperview];
}];
} else if (revealController.frontViewPosition == FrontViewPositionLeft) {
UIView *lock = [[UIView alloc] initWithFrame:self.frontViewController.view.bounds];
lock.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
lock.tag = tagLockView;
lock.backgroundColor = [UIColor blackColor];
lock.alpha = 0;
[lock addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(revealToggle:)]];
[self.frontViewController.view addSubview:lock];
[UIView animateWithDuration:0.75 animations:^{
lock.alpha = 0.333;
}];
}
}
Esta solución para la versión anterior 1.x SWRevealViewController.
Considera esta solución simple, funciona perfecto.
private let DimmingViewTag = 10001
extension UIViewController: SWRevealViewControllerDelegate {
func setupMenuGestureRecognizer() {
revealViewController().delegate = self
view.addGestureRecognizer(revealViewController().panGestureRecognizer())
view.addGestureRecognizer(revealViewController().tapGestureRecognizer())
}
//MARK: - SWRevealViewControllerDelegate
public func revealController(revealController: SWRevealViewController!, didMoveToPosition position: FrontViewPosition) {
if case .Right = position {
let dimmingView = UIView(frame: view.frame)
dimmingView.tag = DimmingViewTag
view.addSubview(dimmingView)
view.bringSubviewToFront(dimmingView)
} else {
view.viewWithTag(DimmingViewTag)?.removeFromSuperview()
}
}
}
Uso simple en UIViewController
:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
setupMenuGestureRecognizer()
}
En ViewDidLoad de tu frontViewController debes agregar un UITapGestureRecognizer
SWRevealViewController *revealController = [self revealViewController];
UITapGestureRecognizer *tap = [revealController tapGestureRecognizer];
tap.delegate = self;
[myView addGestureRecognizer:tap];
Esto debería hacer que la vista trasera se cierre cuando se SWRevealViewController
la vista frontal, que es el comportamiento predeterminado de SWRevealViewController
.
En su controlador de vista de menú , agregue esto:
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.revealViewController.frontViewController.view setUserInteractionEnabled:NO];
}
-(void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[self.revealViewController.frontViewController.view setUserInteractionEnabled:YES];
}
Luego, en el Controlador de vista de elementos de menú , agregue esto en viewDidLoad :
SWRevealViewController *revealController = [self revealViewController];
[revealController tapGestureRecognizer];
También puedes ver mi respuesta here . Aborda el problema en la interacción de la vista frontal (más un gesto de diapositiva).
Gracias a y por su gran ayuda. Aquí está la versión Swift 4 que se deriva de ahí y te ahorra un par de horas:
extension UIViewController: SWRevealViewControllerDelegate {
func setupMenuGestureRecognizer() {
revealViewController().delegate = self
view.addGestureRecognizer(revealViewController().panGestureRecognizer())
view.addGestureRecognizer(revealViewController().tapGestureRecognizer())
}
//MARK: - SWRevealViewControllerDelegate
public func revealController(_ revealController: SWRevealViewController!, willMoveTo position: FrontViewPosition) {
let tagId = 112151
print("revealController delegate called")
if revealController.frontViewPosition == FrontViewPosition.right {
let lock = self.view.viewWithTag(tagId)
UIView.animate(withDuration: 0.25, animations: {
lock?.alpha = 0
}, completion: {(finished: Bool) in
lock?.removeFromSuperview()
}
)
lock?.removeFromSuperview()
} else if revealController.frontViewPosition == FrontViewPosition.left {
let lock = UIView(frame: self.view.bounds)
lock.autoresizingMask = [.flexibleWidth, .flexibleHeight]
lock.tag = tagId
lock.alpha = 0
lock.backgroundColor = UIColor.black
lock.addGestureRecognizer(UITapGestureRecognizer(target: self.revealViewController(), action: #selector(SWRevealViewController.revealToggle(_:))))
self.view.addSubview(lock)
UIView.animate(withDuration: 0.75, animations: {
lock.alpha = 0.333
}
)
}
}
}
Ahora llame a esta función setupMenuGestureRecognizer desde viewDidLoad de su controlador de vista posterior.
O también puede implementar SWRevealViewControllerDelegate directamente en su clase de controlador de vista posterior y usar la función SWRevealViewControllerDelegate en la propia clase.
Poner código debajo en el controlador de vista de menú funciona para mí
@interface SidebarTableViewController() {
UIView* coverView;
}
- (void)viewWillDisappear:(BOOL)animated {
[coverView removeFromSuperview];
//[self.revealViewController.frontViewController.view setUserInteractionEnabled:YES];
// get your window screen size
}
- (void)viewWillAppear:(BOOL)animated {
// get your window screen size
CGRect screenRect = [[UIScreen mainScreen] bounds];
//create a new view with the same size
coverView = [[UIView alloc] initWithFrame:screenRect];
// change the background color to black and the opacity to 0.6
coverView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6];
// add this new view to your main view
[self.revealViewController.frontViewController.view addSubview:coverView];
// [self.revealViewController.frontViewController.view setUserInteractionEnabled:NO];
}
Si está utilizando SWIFT, puede hacer algo como esto, en su frontViewController:
override func viewDidLoad() {
super.viewDidLoad()
if self.revealViewController() != nil {
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
self.view.addGestureRecognizer(self.revealViewController().tapGestureRecognizer())
}
}
El código funciona para los gestos TAP y PAN.
Usé el tapGestureRecognizer pero todavía hay algunos problemas. Intenté esto y trabajé muy bien!
Definir clase:
@interface IgnoreView : UIView
@property (nonatomic, assign) BOOL shouldAllTouchesBeForMe;
@end
Implementar:
@implementation IgnoreView
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
if( self.shouldAllTouchesBeForMe ){
return self;
}
return [super hitTest:point withEvent:event];
}
@end
Luego haga su clase de Vista en Interface Builder de la clase IgnoreView
En su ViewController, entonces, haga:
en - viewDidLoad
self.revealViewController.delegate = self;
[self.view addGestureRecognizer:self.revealViewController.tapGestureRecognizer];
El implemento en su controlador de vista también:
- (void)revealController:(SWRevealViewController *)revealController didMoveToPosition:(FrontViewPosition)position
{
IgnoreView *i = (id)self.view;
i.shouldAllTouchesBeForMe = position == FrontViewPositionRight;
}
¡Y ya está todo listo!
EDITAR: Cambiar la máscara automática de UIView para que se adapte a Swift 2, gracias al comment Marroc
Esta es la versión Swift-SWRevealViewController 2.x de la respuesta de @ avdyushin:
func revealController(revealController: SWRevealViewController!, willMoveToPosition position: FrontViewPosition) {
let tagId = 4207868622
if revealController.frontViewPosition == FrontViewPosition.Right {
let lock = self.view.viewWithTag(tagId)
UIView.animateWithDuration(0.25, animations: {
lock?.alpha = 0
}, completion: {(finished: Bool) in
lock?.removeFromSuperview()
}
)
lock?.removeFromSuperview()
} else if revealController.frontViewPosition == FrontViewPosition.Left {
let lock = UIView(frame: self.view.bounds)
lock.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
lock.tag = tagId
lock.alpha = 0
lock.backgroundColor = UIColor.blackColor()
lock.addGestureRecognizer(UITapGestureRecognizer(target: self.revealViewController(), action: "revealToggle:"))
self.view.addSubview(lock)
UIView.animateWithDuration(0.75, animations: {
lock.alpha = 0.333
}
)
}
}