Cho phép tương tác với một UIView dưới một UIView khác


115

Có cách nào đơn giản để cho phép tương tác với một nút trong UIView nằm dưới một UIView khác - nơi không có đối tượng thực tế từ UIView trên cùng trên đầu nút không?

Ví dụ, tại thời điểm này, tôi có một UIView (A) với một đối tượng ở trên cùng và một đối tượng ở cuối màn hình và không có gì ở giữa. Cái này nằm trên một UIView khác có các nút ở giữa (B). Tuy nhiên, tôi dường như không thể tương tác với các nút ở giữa B.

Tôi có thể thấy các nút trong B - Tôi đã đặt nền của A thành xóa màu - nhưng các nút trong B dường như không nhận được chạm mặc dù thực tế không có đối tượng nào từ A trên đầu các nút đó.

EDIT - Tôi vẫn muốn có thể tương tác với các đối tượng trong UIView hàng đầu

Chắc chắn có một cách đơn giản để làm điều này?


2
Tất cả đều được giải thích ở đây: developer.apple.com/iphone/l Library / document / iPhone / (Nhưng về cơ bản, ghi đè hitTest: withEvent:, họ thậm chí còn cung cấp một mẫu mã.
nash

Tôi đã viết một lớp học nhỏ chỉ vì điều đó. (Đã thêm một ví dụ trong các câu trả lời). Giải pháp ở đó có phần tốt hơn câu trả lời được chấp nhận vì bạn vẫn có thể nhấp vào câu trả lời UIButtondưới dạng bán trong suốt UIViewtrong khi phần không trong suốt của phần UIViewvẫn sẽ phản hồi với các sự kiện chạm.
Segev

Câu trả lời:


97

Bạn nên tạo một lớp con UIView cho chế độ xem hàng đầu của bạn và ghi đè phương thức sau:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    // UIView will be "transparent" for touch events if we return NO
    return (point.y < MIDDLE_Y1 || point.y > MIDDLE_Y2);
}

Bạn cũng có thể xem phương thức hitTest: event:.


19
Middle_y1 / y2 đại diện ở đây là gì?
Jason Renaldo

Không chắc chắn những gì returntuyên bố đó đang làm, nhưng return CGRectContainsPoint(eachSubview.frame, point)làm việc cho tôi. Câu trả lời cực kỳ hữu ích khác
n00neimp0rtant

Doanh nghiệp MIDDLE_Y1 / Y2 chỉ là một ví dụ. Chức năng này sẽ "trong suốt" cho các sự kiện chạm trong MIDDLE_Y1<=y<=MIDDLE_Y2khu vực.
gyim

41

Mặc dù nhiều câu trả lời ở đây sẽ có hiệu quả, tôi hơi ngạc nhiên khi thấy rằng câu trả lời thuận tiện, chung chung và hoàn hảo nhất đã không được đưa ra ở đây. @Ash đã đến gần nhất, ngoại trừ việc có điều gì đó kỳ lạ đang xảy ra với việc trả lại giám sát ... đừng làm điều đó.

Câu trả lời này được lấy từ một câu trả lời tôi đưa ra cho một câu hỏi tương tự, ở đây .

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    UIView *hitView = [super hitTest:point withEvent:event];
    if (hitView == self) return nil;
    return hitView;
}

[super hitTest:point withEvent:event]sẽ trả về chế độ xem sâu nhất trong hệ thống phân cấp của chế độ xem đó đã được chạm vào. Nếu hitView == self(tức là nếu không có nilchế độ xem phụ dưới điểm chạm), hãy quay lại , chỉ định rằng chế độ xem này sẽ không nhận được liên lạc. Cách thức chuỗi phản hồi hoạt động có nghĩa là hệ thống phân cấp chế độ xem ở trên điểm này sẽ tiếp tục được duyệt qua cho đến khi tìm thấy chế độ xem sẽ phản ứng với cảm ứng. Đừng trả lại giám sát, vì nó không phụ thuộc vào quan điểm này cho dù giám sát của nó có nên chấp nhận chạm hay không!

Giải pháp này là:

  • thuận tiện , bởi vì nó không yêu cầu tham chiếu đến bất kỳ chế độ xem / xem / đối tượng nào khác;
  • chung chung , bởi vì nó áp dụng cho bất kỳ chế độ xem nào hoạt động hoàn toàn như một thùng chứa cho các cuộc phỏng vấn có thể chạm được và cấu hình của các cuộc phỏng vấn không ảnh hưởng đến cách thức hoạt động (giống như khi bạn ghi đè pointInside:withEvent:để trả về một vùng có thể chạm cụ thể).
  • Hoàn hảo , không có nhiều mã ... và khái niệm này không khó để khiến bạn phải lo lắng.

Tôi sử dụng điều này thường xuyên đến mức tôi đã trừu tượng hóa nó thành một lớp con để lưu các lớp con xem vô nghĩa cho một ghi đè. Như một phần thưởng, thêm một thuộc tính để làm cho nó có thể cấu hình:

@interface ISView : UIView
@property(nonatomic, assign) BOOL onlyRespondToTouchesInSubviews;
@end

@implementation ISView
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    UIView *hitView = [super hitTest:point withEvent:event];
    if (hitView == self && onlyRespondToTouchesInSubviews) return nil;
    return hitView;
}
@end

Sau đó đi hoang dã và sử dụng chế độ xem này bất cứ nơi nào bạn có thể sử dụng đồng bằng UIView. Cấu hình nó cũng đơn giản như việc thiết onlyRespondToTouchesInSubviewsđể YES.


2
Câu trả lời đúng duy nhất. để rõ ràng, nếu bạn muốn bỏ qua các lần chạm vào một khung nhìn, nhưng không phải với bất kỳ nút (nói) nào có trong chế độ xem , hãy làm như Stuart giải thích. (Tôi thường gọi nó là "chế độ xem chủ sở hữu" vì nó có thể "giữ" một số nút một cách vô hại, nhưng, nó không ảnh hưởng đến bất cứ điều gì "bên dưới" chủ sở hữu.)
Fattie

Một số giải pháp khác sử dụng điểm có vấn đề nếu chế độ xem của bạn có thể cuộn được, như UICableView og UICollectionView và bạn đã cuộn lên hoặc xuống. Tuy nhiên, giải pháp này hoạt động bất kể cuộn.
pyjama 17/2/2016

31

Có một số cách bạn có thể xử lý này. Yêu thích của tôi là ghi đè hitTest: withEvent: trong chế độ xem là một giám sát chung (có thể gián tiếp) đối với các chế độ xem xung đột (âm thanh như bạn gọi là A và B). Ví dụ, một cái gì đó như thế này (ở đây A và B là các con trỏ UIView, trong đó B là "ẩn", thường bị bỏ qua):

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    CGPoint pointInB = [B convertPoint:point fromView:self];

    if ([B pointInside:pointInB withEvent:event])
        return B;

    return [super hitTest:point withEvent:event];
}

Bạn cũng có thể sửa đổi pointInside:withEvent:phương thức như gyim đề xuất. Điều này cho phép bạn đạt được kết quả cơ bản tương tự bằng cách "chọc một lỗ" trong A, ít nhất là cho các cú chạm.

Một cách tiếp cận khác là chuyển tiếp sự kiện, có nghĩa là ghi đè touchesBegan:withEvent:và các phương thức tương tự (như touchesMoved:withEvent:v.v.) để gửi một số chạm đến một đối tượng khác với nơi chúng lần đầu tiên đi. Ví dụ: trong A, bạn có thể viết một cái gì đó như thế này:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    if ([self shouldForwardTouches:touches]) {
        [B touchesBegan:touches withEvent:event];
    }
    else {
        // Do whatever A does with touches.
    }
}

Tuy nhiên, điều này sẽ không luôn luôn hoạt động theo cách bạn mong đợi! Điều chính là các điều khiển tích hợp như UIButton sẽ luôn bỏ qua các lần chạm được chuyển tiếp. Bởi vì điều này, cách tiếp cận đầu tiên là đáng tin cậy hơn.

Có một bài đăng blog tốt giải thích tất cả điều này chi tiết hơn, cùng với một dự án xcode nhỏ đang hoạt động để giới thiệu các ý tưởng, có sẵn ở đây:

http://bynomial.com/blog/?p=74


Vấn đề với giải pháp này - ghi đè hitTest trên giám sát chung - là nó không cho phép chế độ xem bên dưới hoạt động hoàn toàn chính xác khi chế độ xem bên dưới là một trong toàn bộ chế độ xem có thể cuộn (MapView, v.v.). Ghi đè điểm Bên trên chế độ xem hàng đầu như được đề xuất bởi gyim bên dưới hoạt động trong mọi trường hợp theo như tôi có thể nói.
delany

@delany, Điều đó không đúng; bạn có thể có các chế độ xem có thể cuộn bên dưới các chế độ xem khác và để cả hai hoạt động bằng cách ghi đè hitTest. Đây là một số mã mẫu: bynomial.com/blogfiles/Temp32.zip
Tyler

Chào. Không phải tất cả các chế độ xem có thể cuộn - chỉ một số ... Tôi đã thử mã zip của bạn từ phía trên, thay đổi UIScrollView thành MKMapView (ví dụ) và nó không hoạt động. Vòi hoạt động - đó là cuộn có vẻ là vấn đề.
delany

Ok, tôi đã kiểm tra và xác nhận rằng hitTest không hoạt động theo cách bạn có thể muốn với MKMapView. Bạn đã đúng về điều đó, @delany; mặc dù nó hoạt động chính xác với UIScrollView. Tôi tự hỏi tại sao MKMapView thất bại?
Tyler

@Tyler Như bạn đã đề cập, "Điều chính là các điều khiển tích hợp như UIButton sẽ luôn bỏ qua các lần chạm được chuyển tiếp", tôi muốn biết làm thế nào bạn biết điều đó và liệu đó có phải là tài liệu chính thức để giải thích cho hành vi này hay không. Tôi đã phải đối mặt với một vấn đề là khi UIButton có một khung nhìn UIView đơn giản, nó sẽ không phản hồi với các sự kiện chạm trong giới hạn của khung nhìn phụ. Và tôi thấy rằng sự kiện này được chuyển tiếp tới UIButton đúng như hành vi mặc định của UIView, nhưng tôi không chắc đó là một tính năng được chỉ định hay chỉ là một lỗi. Bạn vui lòng cho tôi xem tài liệu về điều này? Cảm ơn bạn rất nhiều chân thành.
Neal.Marlin

29

Bạn phải đặt upperView.userInteractionEnabled = NO;, nếu không, chế độ xem phía trên sẽ chặn các lần chạm.

Phiên bản Trình tạo giao diện của phiên bản này là một hộp kiểm ở cuối bảng Xem thuộc tính được gọi là "Đã bật tương tác người dùng". Bỏ chọn nó và bạn sẽ tốt để đi.


Xin lỗi - nên nói. Tôi vẫn muốn có thể tương tác với các đối tượng trong UIView hàng đầu.
delany

Nhưng UpperView không thể nhận được bất kỳ liên lạc nào, bao gồm nút trong UpperView.
imcaptor

2
Giải pháp này làm việc cho tôi. Tôi không cần quan điểm phía trên để phản ứng với các liên lạc.
TJ

11

Việc triển khai tùy chỉnh pointInside: withEvent: thực sự có vẻ giống như cách để đi, nhưng đối phó với các tọa độ được mã hóa cứng có vẻ kỳ lạ đối với tôi. Vì vậy, tôi đã kết thúc việc kiểm tra xem CGPoint có nằm trong nút CGRect hay không bằng cách sử dụng hàm CGRectContainsPoint ():

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    return (CGRectContainsPoint(disclosureButton.frame, point));
}

8

Gần đây tôi đã viết một lớp sẽ giúp tôi chỉ với điều đó. Sử dụng nó như một lớp tùy chỉnh cho một UIButtonhoặc UIViewsẽ vượt qua các sự kiện chạm được thực hiện trên một pixel trong suốt.

Giải pháp này có phần tốt hơn câu trả lời được chấp nhận vì bạn vẫn có thể nhấp vào câu trả lời UIButtondưới dạng bán trong suốt UIViewtrong khi phần không trong suốt của di UIViewchúc vẫn phản hồi các sự kiện chạm.

QUÀ TẶNG

Như bạn có thể thấy trong GIF, nút Gi hươu cao cổ là một hình chữ nhật đơn giản nhưng các sự kiện chạm vào các khu vực trong suốt được chuyển sang màu vàng UIButtonbên dưới.

Liên kết với lớp


2
Vì mã của bạn không dài đến thế, bạn nên đưa các phần có liên quan vào câu trả lời của mình, trong trường hợp dự án của bạn bị di chuyển hoặc bị xóa vào một thời điểm nào đó trong tương lai.
Gavin

Cảm ơn, giải pháp của bạn hoạt động cho trường hợp của tôi khi tôi cần phần không minh bạch trong UIView của mình để phản hồi các sự kiện chạm, trong khi phần trong suốt thì không. Xuất sắc!
Bruce

@Bruce Rất vui vì nó đã giúp bạn!
Segev

4

Tôi đoán tôi đến hơi muộn bữa tiệc này, nhưng tôi sẽ thêm giải pháp khả thi này:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    UIView *hitView = [super hitTest:point withEvent:event];
    if (hitView != self) return hitView;
    return [self superview];
}

Nếu bạn sử dụng mã này để ghi đè chức năng hitTest tiêu chuẩn của UIView, nó sẽ bỏ qua CHỈ cho chế độ xem. Bất kỳ lượt xem nào của chế độ xem đó sẽ trả về lượt truy cập của họ một cách bình thường và bất kỳ lượt truy cập nào đã chuyển sang chế độ xem được chuyển đến giám sát của nó.

-Tro


1
đây là phương pháp ưa thích của tôi ngoại trừ, tôi không nghĩ bạn nên quay lại [self superview]. tài liệu về phương thức này "Trả về hậu duệ xa nhất của người nhận trong hệ thống phân cấp chế độ xem (bao gồm chính nó) có chứa một điểm được chỉ định" và "Trả về nil nếu điểm nằm hoàn toàn bên ngoài phân cấp chế độ xem của người nhận". Tôi nghĩ bạn nên trở về nil. Khi bạn trở về con số không, quyền điều khiển sẽ chuyển đến giám sát để kiểm tra xem nó có bất kỳ lần truy cập nào hay không. vì vậy về cơ bản, nó sẽ làm điều tương tự, ngoại trừ việc trở lại giám sát có thể phá vỡ một cái gì đó trong tương lai.
jasongregori

Chắc chắn, đó có lẽ là điều khôn ngoan (lưu ý ngày trên câu trả lời ban đầu của tôi - đã thực hiện nhiều mã hóa hơn kể từ đó)
Ash

4

Chỉ cần riff về câu trả lời được chấp nhận và đặt nó ở đây để tôi tham khảo. Câu trả lời được chấp nhận hoạt động hoàn hảo. Bạn có thể mở rộng nó như thế này để cho phép các lượt xem của chế độ xem của bạn nhận được liên lạc, HOẶC chuyển nó cho bất kỳ chế độ xem nào phía sau chúng tôi:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    // If one of our subviews wants it, return YES
    for (UIView *subview in self.subviews) {
        CGPoint pointInSubview = [subview convertPoint:point fromView:self];
        if ([subview pointInside:pointInSubview withEvent:event]) {
            return YES;
        }
    }
    // otherwise return NO, as if userInteractionEnabled were NO
    return NO;
}

Lưu ý: Bạn thậm chí không phải thực hiện đệ quy trên cây phụ, bởi vì mỗi pointInside:withEvent:phương thức sẽ xử lý việc đó cho bạn.


3

Thiết lập thuộc tính userInteraction bị vô hiệu hóa có thể giúp ích. Ví dụ:

UIView * topView = [[TOPView alloc] initWithFrame:[self bounds]];
[self addSubview:topView];
[topView setUserInteractionEnabled:NO];

(Lưu ý: Trong đoạn mã trên, 'tự' đề cập đến một khung nhìn)

Bằng cách này, bạn chỉ có thể hiển thị trên topView, nhưng sẽ không nhận được đầu vào của người dùng. Tất cả những người dùng chạm vào sẽ thông qua chế độ xem này và chế độ xem dưới cùng sẽ phản hồi cho họ. Tôi sẽ sử dụng topView này để hiển thị hình ảnh trong suốt hoặc làm động chúng.


3

Cách tiếp cận này khá sạch sẽ và cho phép các cuộc phỏng vấn minh bạch cũng không phản ứng với các lần chạm. Chỉ cần phân lớp UIViewvà thêm phương thức sau để thực hiện:

@implementation PassThroughUIView

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    for (UIView *v in self.subviews) {
        CGPoint localPoint = [v convertPoint:point fromView:self];
        if (v.alpha > 0.01 && ![v isHidden] && v.userInteractionEnabled && [v pointInside:localPoint withEvent:event])
            return YES;
    }
    return NO;
}

@end

2

Giải pháp của tôi ở đây:

-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    CGPoint pointInView = [self.toolkitController.toolbar convertPoint:point fromView:self];

    if ([self.toolkitController.toolbar pointInside:pointInView withEvent:event]) {
       self.userInteractionEnabled = YES;
    } else {
       self.userInteractionEnabled = NO;
    }

    return [super hitTest:point withEvent:event];
}

Hi vọng điêu nay co ich


2

Có một số thứ bạn có thể làm để chặn cảm ứng trong cả hai chế độ xem.

Nhìn từ trên xuống:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
   // Do code in the top view
   [bottomView touchesBegan:touches withEvent:event]; // And pass them on to bottomView
   // You have to implement the code for touchesBegan, touchesEnded, touchesCancelled in top/bottom view.
}

Nhưng đó là ý tưởng.


Điều này chắc chắn là có thể - nhưng rất nhiều công việc (bạn sẽ phải cuộn các đối tượng nhạy cảm của riêng mình ở lớp dưới cùng (ví dụ như các nút), tôi nghĩ vậy?) Và có vẻ kỳ lạ là người ta sẽ phải tự lăn mình trong việc này cách để có được hành vi dường như là trực quan.
delany

Tôi không chắc có lẽ chúng ta nên thử.
Alexandre Cassagne

2

Đây là phiên bản Swift:

override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {
    return !CGRectContainsPoint(buttonView.frame, point)
}

2

Swift 3

override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
    for subview in subviews {
        if subview.frame.contains(point) {
            return true
        }
    }
    return false
}

1

Tôi chưa bao giờ xây dựng giao diện người dùng hoàn chỉnh bằng bộ công cụ UI, vì vậy tôi không có nhiều kinh nghiệm với nó. Đây là những gì tôi nghĩ nên làm việc mặc dù.

Mỗi UIView, và đây là UIWindow, có một thuộc tính subviews, đó là NSArray chứa tất cả các cuộc phỏng vấn.

Chế độ xem phụ đầu tiên bạn thêm vào chế độ xem sẽ nhận được chỉ số 0 và chỉ mục tiếp theo 1 trở đi. Bạn cũng có thể thay thế addSubview:bằng insertSubview: atIndex:hoặc insertSubview:aboveSubview:và các phương thức như vậy có thể xác định vị trí của khung nhìn phụ của bạn trong hệ thống phân cấp.

Vì vậy, hãy kiểm tra mã của bạn để xem chế độ xem nào bạn thêm trước vào UIWindow. Đó sẽ là 0, số còn lại sẽ là 1.
Bây giờ, từ một trong các cuộc phỏng vấn của bạn, để tiếp cận người khác, bạn sẽ làm như sau:

UIView * theOtherView = [[[self superview] subviews] objectAtIndex: 0];
// or using the properties syntax
UIView * theOtherView = [self.superview.subviews objectAtIndex:0];

Hãy cho tôi biết nếu điều đó làm việc cho trường hợp của bạn!


(bên dưới điểm đánh dấu này là câu trả lời trước của tôi):

Nếu các khung nhìn cần liên lạc với nhau, chúng nên thực hiện thông qua bộ điều khiển (nghĩa là sử dụng mô hình MVC phổ biến ).

Khi bạn tạo một chế độ xem mới, bạn có thể chắc chắn rằng nó tự đăng ký với bộ điều khiển.

Vì vậy, kỹ thuật là đảm bảo các khung nhìn của bạn đăng ký với một bộ điều khiển (có thể lưu trữ chúng theo tên hoặc bất cứ thứ gì bạn thích trong Từ điển hoặc Mảng). Hoặc bạn có thể yêu cầu bộ điều khiển gửi tin nhắn cho bạn hoặc bạn có thể lấy tham chiếu đến chế độ xem và liên lạc trực tiếp với nó.

Nếu chế độ xem của bạn không có liên kết trở lại bộ điều khiển (có thể là trường hợp) thì bạn có thể sử dụng các phương thức singletons và / hoặc lớp để có được tham chiếu đến bộ điều khiển của mình.


Cảm ơn câu trả lời của bạn - nhưng tôi không chắc là tôi hiểu. Cả hai chế độ xem đều có bộ điều khiển - vấn đề là, với một chế độ xem trên cùng, chế độ xem phía dưới không chọn các sự kiện (và chuyển tiếp chúng đến bộ điều khiển của nó), thậm chí không có đối tượng nào thực sự 'chặn' các sự kiện đó trong góc nhìn từ trên xuống.
delany

Bạn có UIWindow ở đầu UIView của chúng tôi không? Nếu bạn làm như vậy, các sự kiện sẽ được truyền bá và bạn không cần phải thực hiện bất kỳ "phép thuật" nào. Hãy đọc về [Cửa sổ và Chế độ xem] [1] tại trung tâm Apple Dev (và bằng mọi cách, hãy thêm một nhận xét khác nếu điều này không giúp ích cho bạn!) [1]: developer.apple.com/iphone/l Library / document / iPhone /
Bắn

Vâng, hoàn toàn - một UIWindow ở đầu phân cấp.
delany

Tôi đã cập nhật câu trả lời của mình để bao gồm mã để đi qua một hệ thống phân cấp lượt xem. Hãy cho tôi biết nếu bạn cần bất kỳ sự giúp đỡ nào khác!
nash

Cảm ơn sự giúp đỡ của bạn - nhưng tôi khá có kinh nghiệm trong việc xây dựng các giao diện này và giao diện hiện tại của tôi được thiết lập chính xác theo như tôi biết. Vấn đề dường như là hành vi mặc định của chế độ xem đầy đủ khi chúng được đặt lên trên các mục khác.
delany

1

Tôi nghĩ rằng cách đúng đắn là sử dụng chuỗi khung nhìn được xây dựng trong hệ thống phân cấp khung nhìn. Đối với các cuộc phỏng vấn của bạn được đẩy lên chế độ xem chính, không sử dụng UIView chung, mà thay vào đó là phân lớp UIView (hoặc một trong các biến thể của nó như UIImageView) để tạo MYView: UIView (hoặc bất kỳ siêu kiểu nào bạn muốn, chẳng hạn như UIImageView). Trong quá trình triển khai cho YourView, hãy triển khai phương thức touchesBegan. Phương thức này sau đó sẽ được gọi khi khung nhìn đó được chạm vào. Tất cả những gì bạn cần có trong triển khai đó là một phương thức thể hiện:

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event ;
{   // cannot handle this event. pass off to super
    [self.superview touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event]; }

touchesBegan này là một api đáp ứng, vì vậy bạn không cần phải khai báo nó trong giao diện công khai hoặc riêng tư của bạn; đó là một trong những phép thuật mà bạn chỉ cần biết. Self.superview này sẽ đưa ra yêu cầu cuối cùng cho viewContoder. Trong viewControll, sau đó, triển khai touchesBegan này để xử lý cảm ứng.

Lưu ý rằng vị trí chạm (CGPoint) được điều chỉnh tự động liên quan đến chế độ xem bao quanh cho bạn khi nó bị bật lên trong chuỗi phân cấp chế độ xem.


1

Chỉ muốn đăng bài này, vì tôi có vấn đề tương tự, đã dành thời gian đáng kể để cố gắng thực hiện câu trả lời ở đây mà không gặp may mắn. Cuối cùng tôi đã làm gì:

 for(UIGestureRecognizer *recognizer in topView.gestureRecognizers)
 {
     recognizer.delegate=self;
     [bottomView addGestureRecognizer:recognizer];   
 }
 topView.abView.userInteractionEnabled=NO; 

và thực hiện UIGestureRecognizerDelegate:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    return YES;
}

Nhìn từ dưới lên là một bộ điều khiển điều hướng với số lượng khoảng cách và tôi có một cánh cửa trên nó có thể đóng lại bằng cử chỉ pan. Toàn bộ điều được nhúng vào một VC khác. Làm việc như người ở. Hi vọng điêu nay co ich.


1

Triển khai Swift 4 cho giải pháp dựa trên HitTest

let hitView = super.hitTest(point, with: event)
if hitView == self { return nil }
return hitView

0

Xuất phát từ câu trả lời xuất sắc và chủ yếu là tuyệt vời của Stuart và triển khai hữu ích của Segev, đây là gói Swift 4 mà bạn có thể thả vào bất kỳ dự án nào:

extension UIColor {
    static func colorOfPoint(point:CGPoint, in view: UIView) -> UIColor {

        var pixel: [CUnsignedChar] = [0, 0, 0, 0]

        let colorSpace = CGColorSpaceCreateDeviceRGB()
        let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)

        let context = CGContext(data: &pixel, width: 1, height: 1, bitsPerComponent: 8, bytesPerRow: 4, space: colorSpace, bitmapInfo: bitmapInfo.rawValue)

        context!.translateBy(x: -point.x, y: -point.y)

        view.layer.render(in: context!)

        let red: CGFloat   = CGFloat(pixel[0]) / 255.0
        let green: CGFloat = CGFloat(pixel[1]) / 255.0
        let blue: CGFloat  = CGFloat(pixel[2]) / 255.0
        let alpha: CGFloat = CGFloat(pixel[3]) / 255.0

        let color = UIColor(red:red, green: green, blue:blue, alpha:alpha)

        return color
    }
}

Và sau đó với hitTest:

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    guard UIColor.colorOfPoint(point: point, in: self).cgColor.alpha > 0 else { return nil }
    return super.hitTest(point, with: event)
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.