ইউআইভিউয়ের সীমা ছাড়িয়ে ইন্টারঅ্যাকশন


94

যখন কোনও ইউআইবাটনের ফ্রেমটি তার পিতামাতার ফ্রেমের বাইরে থাকে তখন কোনও ইউআইবাটন (বা সেই বিষয়ে অন্য কোনও নিয়ন্ত্রণের) স্পর্শ ইভেন্টগুলি পাওয়া সম্ভব? কারণ আমি যখন এটি চেষ্টা করি তখন আমার ইউআইবাটন কোনও ইভেন্ট পেতে সক্ষম হবে বলে মনে হয় না। আমি কীভাবে এটিকে ঘিরে কাজ করব?


4
এটি আমার পক্ষে নিখুঁতভাবে কাজ করে। বিকাশকারী.এপলল.লাইবারি /
ফ্রাঙ্ক লি

4
এই ভাল এবং প্রাসঙ্গিক (অথবা সম্ভবত একটি প্রতারিত) হল stackoverflow.com/a/31420820/8047
ড্যান Rosenstark

উত্তর:


94

হ্যাঁ. আপনি hitTest:withEvent:যে ভিউটি অন্তর্ভুক্ত করেছেন তার চেয়ে বড় পয়েন্টের জন্য একটি ভিউ ফিরে আসার জন্য পদ্ধতিটি ওভাররাইড করতে পারেন। দেখুন UIView ক্লাস রেফারেন্স

সম্পাদনা করুন: উদাহরণ:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    CGFloat radius = 100.0;
    CGRect frame = CGRectMake(-radius, -radius,
                              self.frame.size.width + radius,
                              self.frame.size.height + radius);

    if (CGRectContainsPoint(frame, point)) {
        return self;
    }
    return nil;
}

সম্পাদনা 2: (স্পষ্টকরণের পরে :) বাটনটি পিতামাতার সীমানার মধ্যে রয়েছে বলে নিশ্চিত করার জন্য আপনাকে pointInside:withEvent:বোতামটির ফ্রেম অন্তর্ভুক্ত করার জন্য পিতামাতাকে ওভাররাইড করতে হবে ।

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    if (CGRectContainsPoint(self.view.bounds, point) ||
        CGRectContainsPoint(button.view.frame, point))
    {
        return YES;
    }
    return NO;
}

ওভাররাইডিং পয়েন্টের জন্য কেবলমাত্র কোডটি নোট করুন ইনসাইড বেশ সঠিক নয়। সমন নীচে ব্যাখ্যা হিসাবে, এটি করুন:

-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
    {
    if ( CGRectContainsPoint(self.oversizeButton.frame, point) )
        return YES;

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

নোট করুন যে আপনি সম্ভবত self.oversizeButtonএই ইউআইভিউ সাবক্লাসে আইবিআউটলেট হিসাবে এটি করতে চান ; তারপরে আপনি প্রশ্নের মধ্যে "ওভারসাইজ বোতাম "টিকে টেনে আনতে পারবেন, বিশেষ প্রশ্নে to (বা কোনও কারণে যদি আপনি কোনও প্রকল্পে এটি অনেক কিছু করে চলেছেন তবে আপনার একটি বিশেষ ইউআইবাটন সাবক্লাস রয়েছে এবং আপনি এই শ্রেণীর জন্য আপনার সাবভিউ তালিকার সন্ধান করতে পারেন Hope) আশা করি এটি সহায়তা করবে।


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

এটি বিশেষত এই অংশটি দেখে মনে হয় যেন এটি আমার প্রয়োজন মতো সমাধান নয়: "তবে, হিট টেস্টিং সবসময় পিতামাতার দৃশ্যের বাইরে থাকা পয়েন্টগুলিকে উপেক্ষা করে" .. তবে আমি ভুলভাবে ভুল হতে পারি, আমি কখনও কখনও অ্যাপল রেফারেন্সগুলিকে সত্যিই বিভ্রান্তি দেখি find ..
থমাসম

আহ, আমি এখন বুঝতে পারি। pointInside:withEvent:বোতামের ফ্রেমটি অন্তর্ভুক্ত করতে আপনাকে পিতামাতার ওভাররাইড করতে হবে । আমি আমার উত্তরে কিছু নমুনা কোড যুক্ত করব।
জিনিক

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

4
hitTest:withEvent:এবং pointInside:withEvent:এলাকায় আমার জন্য বলা হয় না যখন আমি একটি বোতাম টিপুন হল অভিভাবকের সীমার মিথ্যা বাইরে। কী ভুল হতে পারে?
আইওসডুড

24

@ জিনিক, আমি আইওএস এসডিকে 5.0 এ কাজ করছি এবং আপনার কোডটি সঠিকভাবে চালানোর জন্য আমাকে এই কাজটি করতে হয়েছিল:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
if (CGRectContainsPoint(button.frame, point)) {
    return YES;
}
return [super pointInside:point withEvent:event]; }

আমার ক্ষেত্রে ধারক দৃষ্টিভঙ্গিটি একটি ইউআইবাটন এবং সমস্ত শিশু উপাদানগুলি ইউআইবিটনও রয়েছে যা প্যারেন্ট ইউআইবুটনের সীমানার বাইরে যেতে পারে।

সেরা


20

প্যারেন্ট ভিউতে আপনি হিট পরীক্ষা পদ্ধতি ওভাররাইড করতে পারেন:

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

    if (CGRectContainsPoint(_myButton.bounds, translatedPoint)) {
        return [_myButton hitTest:translatedPoint withEvent:event];
    }
    return [super hitTest:point withEvent:event];

}

এই ক্ষেত্রে, যদি পয়েন্টটি আপনার বোতামের সীমানার মধ্যে পড়ে, আপনি সেখানে কলটি ফরোয়ার্ড করবেন; যদি তা না হয় তবে মূল বাস্তবায়নে ফিরে যান।


18

আমার ক্ষেত্রে, আমার একটি UICollectionViewCellসাবক্লাস ছিল যা ক UIButton। আমি clipsToBoundsকক্ষে অক্ষম হয়েছি এবং বোতামটি ঘরের সীমানার বাইরে দৃশ্যমান ছিল। যাইহোক, বোতামটি স্পর্শ ইভেন্টগুলি পাচ্ছে না। আমি জ্যাকের উত্তরটি ব্যবহার করে বোতামটিতে টাচ ইভেন্টগুলি সনাক্ত করতে সক্ষম হয়েছি: https://stackoverflow.com/a/30431157/3344977

এখানে একটি সুইফ্ট সংস্করণ রয়েছে:

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

    let translatedPoint = button.convertPoint(point, fromView: self)

    if (CGRectContainsPoint(button.bounds, translatedPoint)) {
        print("Your button was pressed")
        return button.hitTest(translatedPoint, withEvent: event)
    }
    return super.hitTest(point, withEvent: event)
}

সুইফট 4:

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

    let translatedPoint = button.convert(point, from: self)

    if (button.bounds.contains(translatedPoint)) {
        print("Your button was pressed")
        return button.hitTest(translatedPoint, with: event)
    }
    return super.hitTest(point, with: event)
}

ঠিক আমার দৃশ্যটি ছিল। অন্য বিষয়টি হ'ল আপনার এই পদ্ধতিটি কালেকশনভিউকেল ক্লাসের ভিতরে রাখা উচিত।
হামিদ রেজা আনসারী

তবে আপনি কেন ওভাররাইড পদ্ধতিতে বোতামটি ইনজেক্ট করবেন ???
রোমেক্স

10

কেন এমন হচ্ছে?

এটি কারণ যখন আপনার সাবভিউটি আপনার তত্ত্বাবধানের সীমার বাইরে থাকে, তখন সেই সাবভিউতে ঘটে যাওয়া স্পর্শ ইভেন্টগুলি সেই সংক্ষিপ্তরে সরবরাহ করা হবে না। তবে এটি তার তত্ত্বাবধানে সরবরাহ করা হবে

সাবভিউগুলি চাক্ষুষভাবে ক্লিপযুক্ত কিনা তা বিবেচনা না করে, স্পর্শ ইভেন্টগুলি সর্বদা লক্ষ্য দর্শনের তদারকির সীমানার আয়তক্ষেত্রকে সম্মান করে। অন্য কথায়, কোনও দৃশ্যের অংশে ঘটে যাওয়া স্পর্শ ইভেন্টগুলি যা তার তত্ত্বাবধানের সীমানা আয়তক্ষেত্রের বাইরে থাকে সেই দৃশ্যে সরবরাহ করা হয় না। লিঙ্ক

তোমাকে যা করতে হবে?

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

কোড সম্পর্কে কি?

আপনার তত্ত্বাবধানে, বাস্তবায়ন করুন func hitTest(_ point: CGPoint, with event: UIEvent?)

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        if isHidden || alpha == 0 || clipsToBounds { return super.hitTest(point, with: event) }
        // convert the point into subview's coordinate system
        let subviewPoint = self.convert(point, to: subview)
        // if the converted point lies in subview's bound, tell UIKit that subview should be the one that receives this event
        if !subview.isHidden && subview.bounds.contains(subviewPoint) { return subview }
        return super.hitTest(point, with: event)
    }

চিত্তাকর্ষক গোটেচ্যা: আপনাকে অবশ্যই "সর্বোচ্চ অতি-ছোট তদারকিতে" যেতে হবে

সমস্যাটি দেখার বাইরে আপনার "সর্বোচ্চ" ভিউতে আপনাকে "উপরে" যেতে হবে।

সাধারণ উদাহরণ:

বলুন আপনার একটি স্ক্রিন এস রয়েছে, যা একটি ধারক ভিউ সি সহ রয়েছে The আসলে ভি এর বাইরে যা দেখুন

তবে লক্ষ করুন যে বি সি এর বাইরেও is

এই উদাহরণে আপনাকে সমাধানটি override hitTestবাস্তবে সি প্রয়োগ করতে হবে, ভি তে নয় । আপনি যদি এটি ভি তে প্রয়োগ করেন - এটি কিছুই করে না।


4
এই জন্য আপনাকে ধন্যবাদ! এ থেকে উদ্ভূত একটি ইস্যুতে আমি ঘন্টা এবং ঘন্টা ব্যয় করেছি। আপনার পোস্টটি দেওয়ার জন্য সময় দেওয়ার জন্য আমি সত্যই প্রশংসা করি। :)
ClayJ

@ স্কটজু: আপনার উত্তরে আমি একটি গুরুত্বপূর্ণ গোটচ্যা যুক্ত করেছি। অবশ্যই, আপনি আমার সংযোজন মুছতে বা পরিবর্তন করতে নির্দ্বিধায় অনুভব করা উচিত! আবার ধন্যবাদ!
ফ্যাটি

9

দ্রুত:

যেখানে টার্গেটভিউ হল সেই দৃশ্যটি যা আপনি ইভেন্টটি পেতে চান (যা সম্পূর্ণ বা আংশিকভাবে এর প্যারেন্ট ভিউর ফ্রেমের বাইরে থাকতে পারে)।

override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
        let pointForTargetView: CGPoint = targetView.convertPoint(point, fromView: self)
        if CGRectContainsPoint(targetView.bounds, pointForTargetView) {
            return closeButton
        }
        return super.hitTest(point, withEvent: event)
}

5

আমার জন্য (অন্যদের মতো) উত্তরটি পদ্ধতিটিকে ওভাররাইড করা ছিল নাhitTest , বরং pointInsideপদ্ধতিটি ছিল। আমাকে কেবল দুটি জায়গায় এটি করতে হয়েছিল।

সুপারভিউ এই মতামতটি যদি এটি clipsToBoundsসত্য হয়ে থাকে তবে এটি পুরো সমস্যাটি অদৃশ্য হয়ে যাবে। তাই এখানে UIViewসুইফট 3 এ আমার সহজ :

class PromiscuousView : UIView {
    override func point(inside point: CGPoint,
               with event: UIEvent?) -> Bool {
        return true
    }
} 

সাবউভিউ আপনার মাইলেজটি ভিন্ন হতে পারে, তবে আমার ক্ষেত্রে আমাকে pointInsideযে সাবউভিউটির সিদ্ধান্ত নিয়েছিল যে স্পর্শটি সীমা ছাড়িয়েছে তার জন্যও পদ্ধতিটি ওভাররাইট করতে হয়েছিল। খনিটি উদ্দেশ্য-সি-তে রয়েছে, সুতরাং:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    WEPopoverController *controller = (id) self.delegate;
    if (self.takeHitsOutside) {
        return YES;
    } else {
        return [super pointInside:point withEvent:event];
    }
}

এই উত্তরটি (এবং একই প্রশ্নে আরও কয়েকজন) আপনার বোঝাপড়া পরিষ্কার করতে সহায়তা করতে পারে।


2

swift 4.1 আপডেট হয়েছে

একই ইউআইভিউতে স্পর্শ ইভেন্টগুলি পেতে আপনাকে কেবল নিম্নলিখিত ওভাররাইড পদ্ধতিটি যুক্ত করতে হবে, এটি ইউআইভিউতে আলতো চাপানো নির্দিষ্ট ভিউ সনাক্ত করবে যা আবদ্ধের বাইরে রাখা হয়েছে

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    let pointforTargetview:CGPoint = self.convert(point, to: btnAngle)
    if  btnAngle.bounds.contains(pointforTargetview) {
        return  self
    }
    return super.hitTest(point, with: event)
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.