হিটটেষ্ট ব্যবহার করে এর সুপারভিউর ফ্রেমের বাইরে একটি সংক্ষিপ্তসারে ছোঁয়া: ইভেন্ট: সহ:


94

আমার সমস্যা: আমার কাছে একটি সুপারভিউ রয়েছে EditViewযা মূলত পুরো অ্যাপ্লিকেশন ফ্রেমটি MenuViewনিয়ে যায় এবং একটি পর্যালোচনা যা কেবল নীচে ~ 20% নেয় এবং MenuViewতার নিজস্ব পর্যালোচনা থাকে ButtonViewযা আসলে MenuViewসীমানার বাইরে থাকে (এরকম কিছু ButtonView.frame.origin.y = -100:)।

(দ্রষ্টব্য: EditViewঅন্যান্য মতামত রয়েছে যা দর্শন দর্শনক্রমের অংশ নয় MenuView, তবে উত্তরটি প্রভাবিত করতে পারে))

আপনি সম্ভবত ইতিমধ্যে বিষয়টি জানেন: যখন ButtonViewসীমার মধ্যে MenuView(অথবা, আরো নির্দিষ্টভাবে, যখন আমার ছোঁয়া মধ্যে রয়েছে MenuView'র সীমা), ButtonViewসাড়া ঘটনা স্পর্শ করতে। যখন আমার স্পর্শগুলি MenuViewসীমার বাইরে থাকে (তবে এখনও ButtonViewএর সীমার মধ্যে থাকে) তখন কোনও স্পর্শ ইভেন্ট পেল না ButtonView

উদাহরণ:

  • (ঙ) হ'ল EditView, সমস্ত মতামতের পিতামাতা
  • (এম) হ'ল MenuView, এডিটভিউর একটি সাবভিউ
  • (খ) হ'ল ButtonViewমেনুভিউর একটি পর্যালোচনা

চিত্র:

+------------------------------+
|E                             |
|                              |
|                              |
|                              |
|                              |
|+-----+                       |
||B    |                       |
|+-----+                       |
|+----------------------------+|
||M                           ||
||                            ||
|+----------------------------+|
+------------------------------+

(বি) (এম) এর ফ্রেমের বাইরে থাকার কারণে, (বি) অঞ্চলে একটি ট্যাপ কখনই (এম) এ প্রেরণ করা হবে না - আসলে, (এম) কখনও এই ক্ষেত্রে স্পর্শটিকে বিশ্লেষণ করে না এবং স্পর্শটি প্রেরণ করা হয় শ্রেণিবিন্যাসের পরবর্তী বস্তু।

লক্ষ্য: আমি সংগ্রহ করি যে ওভাররাইডিং hitTest:withEvent:এই সমস্যাটি সমাধান করতে পারে তবে ঠিক কীভাবে তা আমি বুঝতে পারি না। আমার ক্ষেত্রে, (আমার 'মাস্টার' সুপারভিউ) এ hitTest:withEvent:ওভাররাইড করা উচিত EditView? বা এটি MenuViewস্পর্শ পাচ্ছে না এমন বোতামের সরাসরি তদারকিতে ওভাররাইড করা উচিত ? না আমি এই সম্পর্কে ভুলভাবে চিন্তা করছি?

এটির যদি দীর্ঘ ব্যাখ্যার প্রয়োজন হয়, তবে একটি ভাল অনলাইন সংস্থান সহায়ক হবে - অ্যাপলের ইউআইভিউ ডক্স বাদে, যা এটি আমার কাছে পরিষ্কার করে দেয় না।

ধন্যবাদ!

উত্তর:


145

আমি স্বীকৃত উত্তরের কোডটিকে আরও জেনেরিক হিসাবে সংশোধন করেছি - এটি এমন কেস পরিচালনা করে যেখানে ভিউটি তার সীমানায় ক্লিপ সাবভিউ দেয় না, লুকিয়ে থাকতে পারে এবং আরও গুরুত্বপূর্ণভাবে: সাবউভিউগুলি জটিল দর্শন শ্রেণিবদ্ধ হলে সঠিক সংক্ষিপ্তসারটি ফিরে আসবে।

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {

    if (self.clipsToBounds) {
        return nil;
    }

    if (self.hidden) {
        return nil;
    }

    if (self.alpha == 0) {
        return nil;
    }

    for (UIView *subview in self.subviews.reverseObjectEnumerator) {
        CGPoint subPoint = [subview convertPoint:point fromView:self];
        UIView *result = [subview hitTest:subPoint withEvent:event];

        if (result) {
            return result;
        }
    }

    return nil;
}

সুইফট 3

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {

    if clipsToBounds || isHidden || alpha == 0 {
        return nil
    }

    for subview in subviews.reversed() {
        let subPoint = subview.convert(point, from: self)
        if let result = subview.hitTest(subPoint, with: event) {
            return result
        }
    }

    return nil
}

আমি আশা করি এটি আরও জটিল ব্যবহারের ক্ষেত্রে এই সমাধানটি ব্যবহার করতে চাইলে যে কাউকে সহায়তা করে।


এটি দেখতে দুর্দান্ত এবং এটি করার জন্য ধন্যবাদ। তবে, একটি প্রশ্ন ছিল: আপনি কেন ফিরছেন [সুপার হিট টেস্ট: পয়েন্ট উইথ ইভেন্ট: ইভেন্ট]; ? স্পর্শকে ট্রিগার করে এমন কোনও মতামত না থাকলে আপনি কি শূন্য করতে পারবেন না? অ্যাপল বলেছে যে কোনও সাবভিউতে টাচ না থাকলে হিট টেস্ট শূন্য করে।
সের পাউস করুন

হুম ... হ্যাঁ, এটি ঠিক ঠিক শোনাচ্ছে। এছাড়াও, সঠিক আচরণের জন্য, বস্তুগুলি বিপরীত ক্রমে পুনরাবৃত্তি করা প্রয়োজন (কারণ শেষটি দৃশ্যমানভাবে শীর্ষে রয়েছে) ম্যাচ করার জন্য সম্পাদিত কোড।
নওম

4
আমি আপনার সলিউশনটি ইউআইবুটনের টাচটি ক্যাপচার করার জন্য ব্যবহার করেছি এবং এটি কোনও ইউআইভিউয়ের অভ্যন্তরে একটি ইউআইকিউলেশনভিউসেল এর অভ্যন্তরে রয়েছে (স্পষ্টতই) একটি ইউআইসি কলিকেশনভিউ। এই তিনটি শ্রেণিতে হিটটেষ্ট: ওভারটেন্ট: ওভাররাইড করার জন্য আমাকে ইউআইকোলিকেশনভিউ এবং ইউআইকোলিকেশনভিউসেলকে সাবক্লাস করতে হয়েছিল। এবং এটি কবজ মত কাজ করে !! ধন্যবাদ !!
ড্যানিয়েল গার্সিয়া

4
কাঙ্ক্ষিত ব্যবহারের উপর নির্ভর করে, এটি হয় [সুপার হিট টেস্ট: পয়েন্ট উইথ: ইভেন্ট] বা শূন্যস্থানে ফিরে আসবে। স্ব-স্ব ফিরিয়ে দেওয়ার ফলে এটি সমস্ত কিছু গ্রহণ করে।
নোটাম

4
এই একই কৌশলটিতে অ্যাপল থেকে একটি প্রশ্নোত্তর প্রযুক্তি সংক্রান্ত ডক এখানে দেওয়া হয়েছে: developer.apple.com/library/ios/qa/qa2013/qa1812.html
জেমস কুয়াং

33

ঠিক আছে, আমি কিছু খনন ও পরীক্ষা করেছি, এখানে কীভাবে hitTest:withEventকাজ করা যায় - কমপক্ষে একটি উচ্চ স্তরে। এই দৃশ্যটি চিত্র:

  • (ঙ) হ'ল এডিটভিউ , সমস্ত দর্শনের পিতামাতা
  • (এম) হ'ল মেনুভিউ , এডিটভিউর একটি সাবভিউ
  • (খ) হ'ল বোতামভিউ , মেনুভিউর একটি সাবভিউ

চিত্র:

+------------------------------+
|E                             |
|                              |
|                              |
|                              |
|                              |
|+-----+                       |
||B    |                       |
|+-----+                       |
|+----------------------------+|
||M                           ||
||                            ||
|+----------------------------+|
+------------------------------+

(বি) (এম) এর ফ্রেমের বাইরে থাকার কারণে, (বি) অঞ্চলে একটি ট্যাপ কখনই (এম) এ প্রেরণ করা হবে না - আসলে, (এম) কখনও এই ক্ষেত্রে স্পর্শটিকে বিশ্লেষণ করে না এবং স্পর্শটি প্রেরণ করা হয় শ্রেণিবিন্যাসের পরবর্তী বস্তু।

তবে আপনি hitTest:withEvent:যদি (এম) প্রয়োগ করেন তবে আবেদনের যে কোনও জায়গায় ট্যাপস (এম) এ প্রেরণ করা হবে (বা এটি তাদের সম্পর্কে কমপক্ষে এটি জানে)। সেক্ষেত্রে স্পর্শটি সামলানোর জন্য আপনি কোড লিখতে পারেন এবং সেই স্পর্শটি গ্রহণ করতে হবে এমন বস্তুটি ফিরিয়ে দিতে পারেন।

আরও সুনির্দিষ্টভাবে: লক্ষ্যটি hitTest:withEvent:হ'ল হিটটি গ্রহণ করা উচিত এমন বস্তুটি ফিরিয়ে দেওয়া। সুতরাং, (এম) এ আপনি হয়ত কোড লিখতে পারেন:

// need this to capture button taps since they are outside of self.frame
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{   
    for (UIView *subview in self.subviews) {
        if (CGRectContainsPoint(subview.frame, point)) {
            return subview;
        }
    }

    // use this to pass the 'touch' onward in case no subviews trigger the touch
    return [super hitTest:point withEvent:event];
}

আমি এখনও এই পদ্ধতিতে এবং এই সমস্যায় খুব নতুন,

আমি আশা করি যে এটি পরে অন্য যে কেউ এই প্রশ্নটিকে হিট করে সহায়তা করে। :)


ধন্যবাদ, এটি আমার পক্ষে কাজ করেছে, যদিও আসলে হিটগুলি গ্রহণ করা উচিত এমন কোন সংক্ষিপ্তসারগুলি দেখার জন্য আমাকে আরও কিছু যুক্তি করতে হয়েছিল। আমি আপনার উদাহরণ বিটিডব্লিউ থেকে একটি অপ্রয়োজনীয় বিরতি সরিয়েছি।
ড্যানিয়েল সাইদী

যখন সাবভিউ ফ্রেমটি পিতামাতার দৃশ্যের বেহন্ড ফ্রেম তখন ক্লিক ইভেন্টটি সাড়া দিচ্ছিল না! আপনার সমাধানটি এই সমস্যার সমাধান করেছে। অনেক অনেক ধন্যবাদ :-)
জীবন

@ toblerpwn (মজাদার ডাকনাম :)) খুব সুন্দর করার জন্য আপনার এই দুর্দান্ত পুরানো উত্তরটি সম্পাদনা করা উচিত (বড় সোনার ক্যাপ ব্যবহার করুন) আপনি কোন শ্রেণিতে এটি যুক্ত করতে হবে। চিয়ার্স!
ফ্যাটি

26

সুইফ্ট 5 এ

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    guard !clipsToBounds && !isHidden && alpha > 0 else { return nil }
    for member in subviews.reversed() {
        let subPoint = member.convert(point, from: self)
        guard let result = member.hitTest(subPoint, with: event) else { continue }
        return result
    }
    return nil
}

এটি কেবলমাত্র কাজ করবে যদি আপনার উপর ওভাররাইড আবেদন সরাসরি "ভুল আচরণ" দেখুন superview
Hudi Ilfeld

2

আমি যা করব তা হল বাটন ভিউ এবং মেনুভিউ উভয়ই একই স্তরে ভিউ হায়ারার্কির সাথে উভয়কেই একটি ধারক স্থানে রেখে দেওয়া থাকে যার ফ্রেম উভয়কে পুরোপুরি ফিট করে। এইভাবে ক্লিপড আইটেমের ইন্টারেক্টিভ অঞ্চলটিকে তত্ত্বাবধানের সীমানার কারণে এড়ানো হবে না।


আমি এই কর্মপরিকল্পনা সম্পর্কেও ভেবেছিলাম - এর অর্থ হ'ল আমাকে কিছু স্থাপনার যুক্তি (বা কিছু গুরুতর কোডের রিফ্যাক্টর) নকল করতে হবে, তবে শেষ পর্যন্ত এটি আমার সেরা পছন্দ হতে পারে ..
toblerpwn

1

যদি আপনার প্যারেন্ট ভিউয়ের ভিতরে আরও অনেকগুলি মতামত থাকে তবে সম্ভবত উপরের সমাধানগুলি ব্যবহার করা হলে সম্ভবত অন্যান্য ইন্টারেক্টিভ ভিউগুলি কাজ করবে না, সেক্ষেত্রে আপনি এই জাতীয় কিছু ব্যবহার করতে পারেন (সুইফট ৩.২ ইন):

class BoundingSubviewsViewExtension: UIView {

    @IBOutlet var targetView: UIView!

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        // Convert the point to the target view's coordinate system.
        // The target view isn't necessarily the immediate subview
        let pointForTargetView: CGPoint? = targetView?.convert(point, from: self)
        if (targetView?.bounds.contains(pointForTargetView!))! {
            // The target view may have its view hierarchy,
            // so call its hitTest method to return the right hit-test view
            return targetView?.hitTest(pointForTargetView ?? CGPoint.zero, with: event)
        }
        return super.hitTest(point, with: event)
    }
}

0

কারও যদি এটির প্রয়োজন হয় তবে এখানে দ্রুত বিকল্প রয়েছে

override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
    if !self.clipsToBounds && !self.hidden && self.alpha > 0 {
        for subview in self.subviews.reverse() {
            let subPoint = subview.convertPoint(point, fromView:self);

            if let result = subview.hitTest(subPoint, withEvent:event) {
                return result;
            }
        }
    }

    return nil
}

0

আপনার দৃষ্টিকোণে কোডের রেখার নীচে রাখুন:

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

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event
{
    CGRect rect = self.bounds;
    BOOL isInside = CGRectContainsPoint(rect, point);
    if(!isInside)
    {
        for (UIView *view in self.subviews)
        {
            isInside = CGRectContainsPoint(view.frame, point);
            if(isInside)
                break;
        }
    }
    return isInside;
}

আরও স্পষ্টতার জন্য, আমার ব্লগে এটি ব্যাখ্যা করা হয়েছিল: "কাস্টম কলআউট: বোতামটি ক্লিকযোগ্য সমস্যা নয়" সম্পর্কিত "গোয়াহেথওয়াইফোনটেক"।

আশা করি ওটা তোমাকে সাহায্য করবে...!!!


আপনার ব্লগটি সরানো হয়েছে, সুতরাং দয়া করে কোথায় ব্যাখ্যাটি পাওয়া যাবে?
ইশাহাক
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.