سؤال

أنا أعمل على بعض التطبيقات / المرافق الأساسية / الألعاب مع iPhone للحصول على قبضة أفضل على ذلك.

لدي حاليا إعداد حيث CGRect يتحرك أينما يتحرك الاصبع، ولكن لا أريد CGRect للذهاب خارج bounds التابع view.

الطريقة الأصلية

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    startLocation = [touch locationInView:self];
    if (startLocation.x < 33){
        touchLocation.x = 33;
            //NSLog(@"Touch At:%f, %f", touchLocation.x, touchLocation.y);
        [self setNeedsDisplay];
    }
    if (startLocation.x > 288){
        touchLocation.x = 288;
            //NSLog(@"Touch At:%f, %f", touchLocation.x, touchLocation.y);
        [self setNeedsDisplay];
    }
    if (startLocation.y < 84){
        touchLocation.y = 84;
            //NSLog(@"Touch At:%f, %f", touchLocation.x, touchLocation.y);
        [self setNeedsDisplay];
    }
    if (startLocation.y > 460){
        touchLocation.y = 460;
            //NSLog(@"Touch At:%f, %f", touchLocation.x, touchLocation.y);
        [self setNeedsDisplay];
    }
    else {
        touchLocation = startLocation;
        [self setNeedsDisplay];
    }
}

مشكلة

لقد جربت بعض الطرق المختلفة لهذا، بما في ذلك استخدام && وجعلها بيان واحد فقط. ال boundaries من الواضح أنها مشفرة بجد، وأنا لست متأكدا من تحديد touchLocation هي أفضل طريقة للحفاظ عليها في bounds.

كل هذا يبدو سخيفا لي عندما أستطيع بسهولة self.view.bounds والحصول على الحدود CGRect. وبعد كيف يمكنني الاستفادة من bounds لفعل هذا؟ هل هناك طريقة أفضل لمنع حدوثها بخلاف الإعداد touchLocation يدويا؟ هل يمكنني وضع حد ما على حد ما على ذلك بدلا من ذلك؟

ماذا عن switch بيان؟ هل يعمل ذلك بشكل أفضل من المحاولةifس؟


محاولة

أحاول الآن استخدام طريقة Rebrad Goss المنشورة أدناه، ومع ذلك لا تعمل؟

Touch Started: (319.000000,350.000000)
Touch Result: (319.000000,350.000000)
Boundaries calculated: X:(0.000000,288.000000) Y(0.000000,328.000000)

اللمس بدأت هي اللمس البدء الفعلي. يجب أن تكون نتيجة اللمس النتيجة التي تم تغييرها.

السجل أعلاه يظهر ذلك خارج المحدد bounds, ، ويعرف أيضا باسم لا يعمل. لن أعيد نشر الرمز الذي كتبه لأنه هو نفسه بالضبط.


مشكلة محاولة

لقد اكتشفت المشكلة. هذا هو نفس الوضع أعلاه على النحو الوارد أعلاه، ولكن مع تسجيل القيم الفردية كما يتم تعيينها.

Touch Started: (293.000000,341.000000)
min x:288.000000
max x:293.000000
min y:328.000000
max y:341.000000
Touch Result: (293.000000,341.000000)
Boundaries calculated: X:(0.000000,288.000000) Y(0.000000,328.000000)

أنا لم أحسب ذلك، لقد قمت بنشرتها هنا بمجرد اكتشافها. وإلا سأنسى التحديث على الإطلاق، أضف الهاء.

سأعود وانظر بالضبط ما يجري في كل من المواقف المحتملة.


خطأ

وجدت مشكلة أخرى، والرمز الذي يحسب boundaries subtracts من maximums, ، ولكن لا add إلى minimums. وبعد هذا مهم لأن هذا هو ما boundary هو ل، لوقف rect من الخروج من الشاشة.

maxX = b.origin.x + b.size.width/* - [box bounds].size.width */;
minX = b.origin.x/* + [box bounds].size.width */;
maxY = b.origin.y + b.size.height/* - [box bounds].size.height */;
minY = b.origin.y?/* + [box bounds].size.height */;

مع هذا ثابت، يمكنني الاستمرار في العمل في المشكلة الأصلية.


خطأ 2

حسنا، لقد قمت بإصلاح مشكلة أخرى. كنت مضيفا إلى y القيمة عند عرضها. نسيت إضافتها إلى هذا الرمز الجديد / ذكرها. يبدو الرمز الآن مثل هذا:

maxX = b.origin.x + b.size.width/* - [box bounds].size.width */;
minX = b.origin.x/* + [box bounds].size.width */;
maxY = b.origin.y + b.size.height/* - [box bounds].size.height + 20*/;
minY = b.origin.y/* + [box bounds].size.height + 20*/;

حجم الدائرة التي يتم عرضها داخل 64px CGRect, ، لذا 20px كان كافيا لعرض الدائرة فوق الإبهام. على الرغم من أن هذا ثابت، إلا أنه لم يساعد في حل مشكلتنا الأصلية.

الزاوية اليسرى العليا:

Touch Started: (14.000000,20.000000)
min x:14.000000
max x:32.000000
min y:20.000000
max y:84.000000
Touch Result: (32.000000,84.000000)
Boundaries calculated: X:(32.000000,288.000000) Y(84.000000,276.000000)

إنه يعمل كما ينبغي، لكنني مرتبك لأن القيم الصحيحة تأتي من MAX بدلاً من MIN. وبعد شيء مختلط هنا.

الزاوية العلوية اليمنى:

Touch Started: (303.000000,21.000000)
min x:288.000000
max x:303.000000
min y:21.000000
max y:84.000000
Touch Result: (303.000000,84.000000)
Boundaries calculated: X:(32.000000,288.000000) Y(84.000000,276.000000)

انها تمنعني من الخروج من الجزء العلوي من الشاشة، مرة أخرى من MAX بدلاً من MIN. وبعد ما زلت قادرا على الطيران من اليمين، كما هو موضح أعلاه.

الزاوية السفلية على اليمين:

Touch Started: (317.000000,358.000000)
min x:288.000000
max x:317.000000
min y:276.000000
max y:358.000000
Touch Result: (317.000000,358.000000)
Boundaries calculated: X:(32.000000,288.000000) Y(84.000000,276.000000)

إنه فشل في كلا الاتجاهين. الآن القيم الفعلية تأتي من MAX, ، والقيم القصوى تأتي من MIN. وبعد ماهذا الهراء؟

أسفل الزاوية اليسرى:

Touch Started: (8.000000,354.000000)
min x:8.000000
max x:32.000000
min y:276.000000
max y:354.000000
Touch Result: (32.000000,354.000000)
Boundaries calculated: X:(32.000000,288.000000) Y(84.000000,276.000000)

من الناحية المتوقعة، عملت فقط من أجل الحد الأدنى للقيمة. ما زلت مرتبكا للغاية فيما يتعلق بما يفترض بهذه المهام. سوف تكون موضع تقدير كبير!


تم حلها!

يسحب طريقنا الطويل إلى قريب وحسن الحظ. لذلك، لأنني لم يكن لدي أدنى فكرة، إليك ما MIN و MAX فعل. لم يكن الأمر واضحا في البداية بسبب الارتباك الذي حدث.

MAX(x,y) will output the larger of the two numbers
// MAX(13,37) = 37
MIN(x,y) will output the smallest of the two numbers
// MIN(13,37) = 13

لذلك هذا هو ما عليك القيام به للاستفادة من هذه الوظائف بشكل صحيح في هذا الموقف:

1. حساب القيم القصوى والحد الأدنى ل X و Y.

يتم احتساب أقل قيمة لكل منها

view.origin + keepOnScreenRect.width  

يتم احتساب أعلى قيمة لكل منها

view.origin + view.size.height/width - keepOnScreenRect.height/width

لا تنس إزاحة الإصبع!
إذا كنت تفعل ما فعلته، ولديه KeepsCreenRect وضعه أعلى قليلا من إصبع المستخدم، يجب عليك فقط إضافة الإزاحة الإضافية إلى الحد الأقصى لقيمة Y، حيث أن الحد الأدنى لقيمة y هو الجزء السفلي من الشاشة / العرض، الذي أنت غير قادر جسديا على الذهاب أقل من 0 في.

إذا كنت تتساءل لماذا يتم ذلك، فذلك لأن المستخدم لا يستطيع رؤيته من خلال إصبعه.

2. احصل على موقع اللمس touchesBegan:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    startTouchLocation = [touch locationInView:self];
    NSLog(@"Touch Started: (%f,%f)", startTouchLocation.x, startTouchLocation.y);

3. تطبيق القيود الرياضية:

أولا، نحصل على MAX, أو أعلى قيمة، من كل من أقل قيمة ممكنة وفقا لحدودنا، minX, ، و startTouchLocation, ، ل X. وبعد هذا يحسب الحد الأقصى للجانب الأيسر من الشاشة. نتيجة ذلك تم ضبطها على currentTouchLocation.

currentTouchLocation.x = MAX(minX, startTouchLocation.x);

ثانيا، نحصل على MIN, ، أو أدنى قيمة، من كل من أعلى قيمة ممكنة وفقا لحدودنا، maxX, ، و currentTouchLocation, ، ل X. وبعد لاحظ أننا لا نستخدم موقع المس باللمس الأصلي، ولكن بدلا من ذلك الموقع الناتج MAX وظيفة استخدمنا للتو. تم فحص هذه القيمة بالفعل للجانب الأيسر من الشاشة، لذلك نتحقق من اليمين.

currentTouchLocation.x = MIN(maxX, currentTouchLocation.x);

هذا يعطينا X الموقع مضمون ليكون ضمن حدودنا. بعد ذلك أداء نفس الشيء Y.

currentTouchLocation.y = MAX(minY, startTouchLocation.y);
currentTouchLocation.y = MIN(maxY, currentTouchLocation.y);

مع كل هذا انتهى، يمكننا الآن سرد الرأي لإعادة رسم نفسه ولم تعد تخشى أن تقطع مستطيلنا القليل جميل بأي شكل من الأشكال.

[self setNeedsDisplay];

منتج منتهي

/* Generates the limits based on the view's size, taking into account 
   the width/height of the rect being displayed in it. This should only
   be run once, unless the size of the view changes, in which case limits
   would have to be recalculated. The same goes for if you were to change
   the size of the displaying rect after calculation */

- (void)boundsCalculation {
    CGRect viewBounds = [self bounds];

        // calculate constraints
    maxX = viewBounds.origin.x + viewBounds.size.width - 32;
    minX = viewBounds.origin.x + 32;
    maxY = viewBounds.origin.y + viewBounds.size.height - 32;
    minY = viewBounds.origin.y + 84;
    NSLog(@"Boundaries calculated: X:(%f,%f) Y(%f,%f)", minX, maxX, minY, maxY);
}

/* Magic goodness that happens when the user touches the screen.
   Note that we don't calculate the bounds every time the user touches
   the screen, that would be silly. */

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    startTouchLocation = [touch locationInView:self];
    NSLog(@"Touch Started: (%f,%f)", startTouchLocation.x, startTouchLocation.y);

        // apply constraints
            // highest x value between the lowest allotted x value and touch
    currentTouchLocation.x = MAX(minX, startTouchLocation.x);
            // lowest x value between the highest allotted x value and touch
    currentTouchLocation.x = MIN(maxX, currentTouchLocation.x);
            // highest y value between the lowest allotted y value and touch
    currentTouchLocation.y = MAX(minY, startTouchLocation.y);
            // lowest y value between the highest allotted y value and touch
    currentTouchLocation.y = MIN(maxY, currentTouchLocation.y);
           // NSLog(@"Touch Result: (%f,%f)", currentTouchLocation.x, currentTouchLocation.y);

           // If you don't do this you won't see anything
    [self setNeedsDisplay];
}

كان اليوم يوما جيدا للتعلم.

هل كانت مفيدة؟

المحلول

تريد بالتأكيد استخدام حدودها Superview لتقييد الحركة.

لا تتصل setneedsdisplay في كثير من الأحيان. اتصل به مرة واحدة في نهاية الطريقة. من المحتمل أن تجمع دون داع.

كنت أستخدم شيئا مثل ما يلي لإنجاز هذا.

// define these variables where ever you'd like
static float maxX = 0.;
static float maxY = 0.;
static float minX = 0.;
static float minY = 0.;

- (void)setupView {
    CGRect b = [self bounds];

    // calculate constraints
    maxX = b.origin.x + b.size.width/* - [box bounds].size.width */;
    minX = b.origin.x;
    maxY = b.origin.y + b.size.height/* - [box bounds].size.height */;
    minY = b.origin.y;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    startLocation = [touch locationInView:self];

    // apply constraints
    touchLocation.x = MIN(maxX, startLocation.x);
    touchLocation.x = MAX(minX, startLocation.x);
    touchLocation.y = MIN(maxY, startLocation.y);
    touchLocation.y = MAX(minY, startLocation.y);

    [self setNeedsDisplay];
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top