โกโก้: อะไรคือความแตกต่างระหว่างกรอบและขอบเขต?


587

UIViewและ subclasses ของทุกคนมีคุณสมบัติและframe boundsความแตกต่างคืออะไร?


1
ทำความเข้าใจกับmacoscope.com/blog/understanding-frame
onmyway133

สำหรับผมคำอธิบายที่รัดกุมมากที่สุดคือที่นี่: videos.raywenderlich.com/courses/99-scroll-view-school/lessons/...
Vlad

1
ไม่มีอะไรรัดกุมเกี่ยวกับวิดีโอ 2:30 ฉันสามารถอ่านหนึ่งหรือสองประโยคได้เร็วกว่า 2:30
dsjoerg

สำหรับฉันมันชัดเจนมากขึ้นถ้าฉันคิดแบบนี้: Frame = ขอบเขตและตำแหน่ง
Serg

คำตอบ:


902

ขอบเขตของUIViewเป็นรูปสี่เหลี่ยมผืนผ้าแสดงเป็นสถานที่ (x, y) และขนาด (กว้างความสูง) เมื่อเทียบกับระบบพิกัดของตัวเอง (0,0)

กรอบของUIViewเป็นรูปสี่เหลี่ยมผืนผ้าแสดงเป็นที่ตั้ง (x, y) และขนาด (กว้างความสูง) เทียบกับ SuperView มันอยู่ภายใน

ลองจินตนาการถึงมุมมองที่มีขนาด 100x100 (กว้าง x สูง) ในตำแหน่งที่ 25,25 (x, y) ของผู้ควบคุม รหัสต่อไปนี้จะพิมพ์ขอบเขตและกรอบของมุมมองนี้:

// This method is in the view controller of the superview
- (void)viewDidLoad {
    [super viewDidLoad];

    NSLog(@"bounds.origin.x: %f", label.bounds.origin.x);
    NSLog(@"bounds.origin.y: %f", label.bounds.origin.y);
    NSLog(@"bounds.size.width: %f", label.bounds.size.width);
    NSLog(@"bounds.size.height: %f", label.bounds.size.height);

    NSLog(@"frame.origin.x: %f", label.frame.origin.x);
    NSLog(@"frame.origin.y: %f", label.frame.origin.y);
    NSLog(@"frame.size.width: %f", label.frame.size.width);
    NSLog(@"frame.size.height: %f", label.frame.size.height);
}

และผลลัพธ์ของรหัสนี้คือ:

bounds.origin.x: 0
bounds.origin.y: 0
bounds.size.width: 100
bounds.size.height: 100

frame.origin.x: 25
frame.origin.y: 25
frame.size.width: 100
frame.size.height: 100

ดังนั้นเราจะเห็นได้ว่าในทั้งสองกรณีความกว้างและความสูงของมุมมองจะเหมือนกันโดยไม่คำนึงว่าเรากำลังดูขอบเขตหรือกรอบ สิ่งที่แตกต่างกันคือตำแหน่ง x, y ของมุมมอง ในกรณีของขอบเขตพิกัด x และ y อยู่ที่ 0,0 เนื่องจากพิกัดเหล่านี้สัมพันธ์กับมุมมองของตัวเอง อย่างไรก็ตามพิกัดเฟรม x และ y นั้นสัมพันธ์กับตำแหน่งของมุมมองภายในมุมมองพาเรนต์ (ซึ่งก่อนหน้านี้เราบอกว่าอยู่ที่ 25,25)

นอกจากนี้ยังมีการนำเสนอที่ยอดเยี่ยมที่ครอบคลุม UIViews ดูสไลด์ 1-20 ซึ่งไม่เพียง แต่อธิบายความแตกต่างระหว่างเฟรมและขอบเขต แต่ยังแสดงตัวอย่างด้วยภาพ


37
ดังนั้นจะไม่ x, y สำหรับขอบเขตเสมอเป็น 0,0 เนื่องจากตำแหน่งของวัตถุใน ... ตัวเอง หรือคุณสามารถให้สถานการณ์ที่มันจะไม่?
mk12

5
เท่าที่ผมรู้ว่าที่มาของขอบเขตจะเป็น 0,0
เจียงไคเชก

77
ที่จริงแล้วข้อ จำกัด ถิ่นกำเนิดอาจเป็นอะไรที่นอกเหนือจาก 0,0 ใช้ setBoundsOrigin: เพื่อย้าย / แปลต้นกำเนิด ดู "ดูเรขาคณิต" ใน "ดูคู่มือการเขียนโปรแกรมสำหรับโกโก้" สำหรับข้อมูลเพิ่มเติม
Meltemi

127
UIScrollView เป็นตัวอย่างที่ขอบเขตสามารถเลื่อนเพื่อแสดงขอบเขตเนื้อหาที่แตกต่างภายในมุมมอง
แบรด Larson

92
เคล็ดลับเล็ก ๆ - การใช้ NSStringFromCGRect สามารถประหยัดเวลาในการบันทึก rects
เบริลเลียม

647

คำตอบสั้น ๆ

frame = ตำแหน่งและขนาดของมุมมองโดยใช้ระบบพิกัดของมุมมองพาเรนต์

  • สำคัญสำหรับ: การวางมุมมองในพาเรนต์

bounds = ตำแหน่งและขนาดของมุมมองโดยใช้ระบบพิกัดของตัวเอง

  • สำคัญสำหรับ: การวางเนื้อหาหรือมุมมองย่อยไว้ในตัวของมันเอง

คำตอบโดยละเอียด

เพื่อช่วยให้ฉันจำกรอบฉันคิดถึงกรอบรูปบนผนังกรอบรูปบนผนังกรอบรูปเหมือนขอบของมุมมอง ฉันแขวนรูปภาพได้ทุกที่ที่ต้องการบนผนัง ในทำนองเดียวกันฉันสามารถใส่มุมมองได้ทุกที่ที่ฉันต้องการภายในมุมมองหลัก (เรียกอีกอย่างหนึ่งว่า superview) มุมมองของผู้ปกครองเป็นเหมือนกำแพง ที่มาของระบบพิกัดใน iOS นั้นอยู่ที่มุมบนซ้าย เราสามารถใส่มุมมองของเราที่จุดกำเนิดของ superview โดยการตั้งค่าพิกัด xy ของกรอบการดูเป็น (0, 0) ซึ่งเหมือนกับแขวนรูปภาพของเราไว้ที่มุมซ้ายบนสุดของผนัง หากต้องการเลื่อนไปทางขวาให้เพิ่ม x เพื่อเลื่อนลงเพิ่มขึ้น y

เพื่อช่วยให้ฉันจำขอบเขตได้ฉันนึกถึงสนามบาสเก็ตบอลซึ่งบางครั้งบาสเก็ตก็ล้มลงบาสเก็ตที่ได้รับการเคาะออกจากขอบเขตคุณกำลังเลี้ยงลูกฟุตบอลอยู่ทั่วสนามบาสเก็ตบอล แต่คุณไม่สนใจว่าตัวเองอยู่ที่ไหนในสนาม อาจเป็นในโรงยิมหรือนอกโรงเรียนมัธยมหรือหน้าบ้านของคุณ มันไม่สำคัญ คุณแค่ต้องการเล่นบาสเก็ตบอล ในทำนองเดียวกันระบบพิกัดสำหรับขอบเขตของมุมมองจะสนใจเฉพาะมุมมองเท่านั้น ไม่ทราบว่ามีมุมมองใดอยู่ในมุมมองพาเรนต์ จุดเริ่มต้นขอบเขต (จุด (0, 0) ตามค่าเริ่มต้น) คือมุมซ้ายบนของมุมมอง มุมมองย่อยใด ๆ ที่มุมมองนี้ถูกจัดวางไว้สัมพันธ์กับประเด็นนี้ มันเหมือนกับการพาบาสเก็ตบอลไปที่มุมซ้ายด้านหน้าของศาล

ตอนนี้ความสับสนเกิดขึ้นเมื่อคุณพยายามเปรียบเทียบเฟรมและขอบเขต แม้ว่ามันจะไม่เลวร้ายอย่างที่คิดในตอนแรก ลองใช้รูปภาพเพื่อช่วยให้เราเข้าใจ

กรอบ vs ขอบเขต

ในภาพแรกทางซ้ายเรามีมุมมองที่อยู่ด้านซ้ายบนของมุมมองหลัก สี่เหลี่ยมสีเหลืองแสดงถึงเฟรมของมุมมอง ทางด้านขวาเราจะเห็นมุมมองอีกครั้ง แต่คราวนี้มุมมองหลักจะไม่ปรากฏ นั่นเป็นเพราะขอบเขตไม่รู้เกี่ยวกับมุมมองหลัก สี่เหลี่ยมสีเขียวแสดงถึงขอบเขตของมุมมอง จุดสีแดงในภาพทั้งสองหมายถึงแหล่งที่มาของกรอบหรือขอบเขต

Frame
    origin = (0, 0)
    width = 80
    height = 130

Bounds 
    origin = (0, 0)
    width = 80
    height = 130

ป้อนคำอธิบายรูปภาพที่นี่

ดังนั้นกรอบและขอบเขตจึงเหมือนกันในภาพนั้น ลองดูตัวอย่างที่พวกเขาแตกต่างกัน

Frame
    origin = (40, 60)  // That is, x=40 and y=60
    width = 80
    height = 130

Bounds 
    origin = (0, 0)
    width = 80
    height = 130

ป้อนคำอธิบายรูปภาพที่นี่

ดังนั้นคุณจะเห็นได้ว่าการเปลี่ยนพิกัด xy ของเฟรมเลื่อนไปในมุมมองพาเรนต์ แต่เนื้อหาของมุมมองนั้นยังคงเหมือนเดิม ขอบเขตไม่มีความคิดว่าสิ่งใดที่แตกต่าง

ถึงตอนนี้ความกว้างและความสูงของทั้งเฟรมและขอบเขตเท่ากันทุกประการ นั่นไม่จริงเสมอไป ดูว่าเกิดอะไรขึ้นถ้าเราหมุนมุมมอง 20 องศาตามเข็มนาฬิกา (การหมุนทำได้โดยใช้การแปลงดูเอกสารประกอบและตัวอย่างมุมมองและเลเยอร์เหล่านี้สำหรับข้อมูลเพิ่มเติม)

Frame
    origin = (20, 52)  // These are just rough estimates.
    width = 118
    height = 187

Bounds 
    origin = (0, 0)
    width = 80
    height = 130

ป้อนคำอธิบายรูปภาพที่นี่

คุณจะเห็นว่าขอบเขตยังคงเหมือนเดิม พวกเขายังไม่รู้ว่าเกิดอะไรขึ้น! แม้ว่าค่าเฟรมจะเปลี่ยนไปทั้งหมด

ทีนี้มันง่ายกว่าที่จะเห็นความแตกต่างระหว่างเฟรมกับขอบเขตใช่ไหม? บทความที่คุณอาจไม่เข้าใจเฟรมและขอบเขตกำหนดกรอบมุมมองเป็น

... กล่องขอบเขตที่เล็กที่สุดของมุมมองนั้นเกี่ยวกับระบบการปกครองของผู้ประสานงานรวมถึงการแปลงใด ๆ ที่ใช้กับมุมมองนั้น

เป็นสิ่งสำคัญที่จะต้องทราบว่าหากคุณเปลี่ยนมุมมองกรอบจะไม่ได้กำหนด ดังนั้นจริง ๆ แล้วกรอบสีเหลืองที่ฉันวาดรอบขอบเขตสีเขียวที่หมุนในภาพด้านบนไม่เคยมีอยู่จริง นั่นหมายความว่าถ้าคุณหมุนปรับขนาดหรือทำการแปลงอื่น ๆ คุณไม่ควรใช้ค่าเฟรมอีกต่อไป คุณยังสามารถใช้ค่าขอบเขตได้ เอกสารของ Apple เตือนว่า:

สำคัญ:ถ้าtransformคุณสมบัติของมุมมองไม่มีการแปลงข้อมูลเฉพาะตัวเฟรมของมุมมองนั้นจะไม่ได้ถูกกำหนดและผลลัพธ์ของพฤติกรรมการเปลี่ยนขนาดอัตโนมัติจะเป็นเช่นนั้น

ค่อนข้างโชคร้ายเกี่ยวกับการปรับขนาดอัตโนมัติ .... มีบางอย่างที่คุณสามารถทำได้

สถานะเอกสารของ Apple:

เมื่อแก้ไขtransformคุณสมบัติของมุมมองของคุณการแปลงทั้งหมดจะดำเนินการสัมพันธ์กับจุดกึ่งกลางของมุมมอง

ดังนั้นหากคุณต้องการย้ายมุมมองไปรอบ ๆ ในพาเรนต์หลังจากการแปลงเสร็จสิ้นคุณสามารถทำได้โดยเปลี่ยนview.centerพิกัด ชอบframe, centerใช้ระบบการประสานงานในมุมมองของผู้ปกครอง

ตกลงมากำจัดการหมุนของเราและมุ่งไปที่ขอบเขต จนถึงจุดเริ่มต้นขอบเขตยังคงอยู่ที่ (0, 0) ไม่จำเป็นต้องทำ เกิดอะไรขึ้นถ้ามุมมองของเรามีมุมมองย่อยขนาดใหญ่ที่ใหญ่เกินกว่าจะแสดงพร้อมกันทั้งหมด เราจะทำให้มันเป็นUIImageViewภาพขนาดใหญ่ นี่คือภาพที่สองของเราจากด้านบนอีกครั้ง แต่คราวนี้เราสามารถเห็นเนื้อหาทั้งหมดของมุมมองย่อยของมุมมองของเราจะเป็นอย่างไร

Frame
    origin = (40, 60)
    width = 80
    height = 130

Bounds 
    origin = (0, 0)
    width = 80
    height = 130

ป้อนคำอธิบายรูปภาพที่นี่

เฉพาะมุมซ้ายบนของรูปภาพเท่านั้นที่สามารถใส่ในขอบเขตของมุมมองได้ ทีนี้ลองดูว่าเกิดอะไรขึ้นถ้าเราเปลี่ยนพิกัดจุดกำเนิดของขอบเขต

Frame
    origin = (40, 60)
    width = 80
    height = 130

Bounds 
    origin = (280, 70)
    width = 80
    height = 130

ป้อนคำอธิบายรูปภาพที่นี่

เฟรมไม่ได้ย้ายไปอยู่ใน superview แต่เนื้อหาภายในเฟรมเปลี่ยนไปเนื่องจากจุดเริ่มต้นของขอบเขตสี่เหลี่ยมผืนผ้าเริ่มต้นที่ส่วนอื่นของมุมมอง นี่เป็นแนวคิดทั้งหมดที่อยู่เบื้องหลังUIScrollViewและเป็นคลาสย่อย (ตัวอย่างเช่น a UITableView) ดูการทำความเข้าใจกับ UIScrollViewสำหรับคำอธิบายเพิ่มเติม

ควรใช้เฟรมเมื่อใดและเมื่อใด

เนื่องจากframeเกี่ยวข้องกับตำแหน่งของมุมมองในมุมมองพาเรนต์คุณจึงใช้มุมมองนั้นเมื่อคุณทำการเปลี่ยนแปลงภายนอกเช่นเปลี่ยนความกว้างหรือค้นหาระยะห่างระหว่างมุมมองและด้านบนของมุมมองพาเรนต์

ใช้boundsเวลาที่คุณทำการเปลี่ยนแปลงภายในเช่นวาดสิ่งหรือจัดเรียงหัวข้อย่อยภายในมุมมอง ใช้ขอบเขตเพื่อให้ได้ขนาดของมุมมองถ้าคุณทำ transfomation กับมัน

บทความสำหรับการวิจัยเพิ่มเติม:

เอกสารของ Apple

คำถาม StackOverflow ที่เกี่ยวข้อง

แหล่งข้อมูลอื่น ๆ

ฝึกฝนตัวเอง

นอกจากการอ่านบทความข้างต้นมันช่วยฉันได้มากในการสร้างแอปทดสอบ คุณอาจต้องการลองทำสิ่งที่คล้ายกัน (ฉันได้ความคิดจากหลักสูตรวิดีโอนี้แต่น่าเสียดายที่มันไม่ฟรี)

ป้อนคำอธิบายรูปภาพที่นี่

นี่คือรหัสสำหรับการอ้างอิงของคุณ:

import UIKit

class ViewController: UIViewController {


    @IBOutlet weak var myView: UIView!

    // Labels
    @IBOutlet weak var frameX: UILabel!
    @IBOutlet weak var frameY: UILabel!
    @IBOutlet weak var frameWidth: UILabel!
    @IBOutlet weak var frameHeight: UILabel!
    @IBOutlet weak var boundsX: UILabel!
    @IBOutlet weak var boundsY: UILabel!
    @IBOutlet weak var boundsWidth: UILabel!
    @IBOutlet weak var boundsHeight: UILabel!
    @IBOutlet weak var centerX: UILabel!
    @IBOutlet weak var centerY: UILabel!
    @IBOutlet weak var rotation: UILabel!

    // Sliders
    @IBOutlet weak var frameXSlider: UISlider!
    @IBOutlet weak var frameYSlider: UISlider!
    @IBOutlet weak var frameWidthSlider: UISlider!
    @IBOutlet weak var frameHeightSlider: UISlider!
    @IBOutlet weak var boundsXSlider: UISlider!
    @IBOutlet weak var boundsYSlider: UISlider!
    @IBOutlet weak var boundsWidthSlider: UISlider!
    @IBOutlet weak var boundsHeightSlider: UISlider!
    @IBOutlet weak var centerXSlider: UISlider!
    @IBOutlet weak var centerYSlider: UISlider!
    @IBOutlet weak var rotationSlider: UISlider!

    // Slider actions
    @IBAction func frameXSliderChanged(sender: AnyObject) {
        myView.frame.origin.x = CGFloat(frameXSlider.value)
        updateLabels()
    }
    @IBAction func frameYSliderChanged(sender: AnyObject) {
        myView.frame.origin.y = CGFloat(frameYSlider.value)
        updateLabels()
    }
    @IBAction func frameWidthSliderChanged(sender: AnyObject) {
        myView.frame.size.width = CGFloat(frameWidthSlider.value)
        updateLabels()
    }
    @IBAction func frameHeightSliderChanged(sender: AnyObject) {
        myView.frame.size.height = CGFloat(frameHeightSlider.value)
        updateLabels()
    }
    @IBAction func boundsXSliderChanged(sender: AnyObject) {
        myView.bounds.origin.x = CGFloat(boundsXSlider.value)
        updateLabels()
    }
    @IBAction func boundsYSliderChanged(sender: AnyObject) {
        myView.bounds.origin.y = CGFloat(boundsYSlider.value)
        updateLabels()
    }
    @IBAction func boundsWidthSliderChanged(sender: AnyObject) {
        myView.bounds.size.width = CGFloat(boundsWidthSlider.value)
        updateLabels()
    }
    @IBAction func boundsHeightSliderChanged(sender: AnyObject) {
        myView.bounds.size.height = CGFloat(boundsHeightSlider.value)
        updateLabels()
    }
    @IBAction func centerXSliderChanged(sender: AnyObject) {
        myView.center.x = CGFloat(centerXSlider.value)
        updateLabels()
    }
    @IBAction func centerYSliderChanged(sender: AnyObject) {
        myView.center.y = CGFloat(centerYSlider.value)
        updateLabels()
    }
    @IBAction func rotationSliderChanged(sender: AnyObject) {
        let rotation = CGAffineTransform(rotationAngle: CGFloat(rotationSlider.value))
        myView.transform = rotation
        updateLabels()
    }

    private func updateLabels() {

        frameX.text = "frame x = \(Int(myView.frame.origin.x))"
        frameY.text = "frame y = \(Int(myView.frame.origin.y))"
        frameWidth.text = "frame width = \(Int(myView.frame.width))"
        frameHeight.text = "frame height = \(Int(myView.frame.height))"
        boundsX.text = "bounds x = \(Int(myView.bounds.origin.x))"
        boundsY.text = "bounds y = \(Int(myView.bounds.origin.y))"
        boundsWidth.text = "bounds width = \(Int(myView.bounds.width))"
        boundsHeight.text = "bounds height = \(Int(myView.bounds.height))"
        centerX.text = "center x = \(Int(myView.center.x))"
        centerY.text = "center y = \(Int(myView.center.y))"
        rotation.text = "rotation = \((rotationSlider.value))"

    }

}

ดูเหมือนว่าความกว้างและความสูงของขอบเขตนั้นซ้ำซ้อนและคุณสมบัติ "แหล่งกำเนิด" น่าจะเพียงพอแล้ว (เช่นเดียวกับ Flash)
Ian Warburton

ใช้ขอบเขตสำหรับ "เช่นวาดสิ่งหรือจัดเรียงมุมมองย่อยภายในมุมมอง" คุณหมายถึงว่าฉันมี viewController ซึ่งมีสองปุ่มฉันควรวางปุ่มโดยใช้ 'ขอบเขต' ของ viewController หรือไม่! ฉันใช้กรอบมุมมองเสมอ ...
ฮันนี่

@Honey ฉันมีความแข็งแรงในทักษะ iOS เล็กน้อยเนื่องจากฉันทำงานกับ Android มาเป็นปีที่แล้ว ฉันเชื่อว่ามุมมองรูทของ View Controller เติมหน้าจอดังนั้นเฟรมและขอบเขตควรจะเหมือนกัน
Suragch

5
สร้างgithub.com/maniramezan/FrameVsBounds.git repo ตามแอพตัวอย่างที่ให้ไว้ที่นี่เพื่อช่วยในการทำความเข้าใจมุมมองboundsvs frame
manman

1
@IanWarburton เมื่อมุมมองถูกหมุนความกว้างและความสูงของขอบเขตจะไม่ตรงกับเฟรมดังนั้นจึงไม่ซ้ำซ้อน
Edward Brey

43

พยายามเรียกใช้รหัสด้านล่าง

- (void)viewDidLoad {
    [super viewDidLoad];
    UIWindow *w = [[UIApplication sharedApplication] keyWindow];
    UIView *v = [w.subviews objectAtIndex:0];

    NSLog(@"%@", NSStringFromCGRect(v.frame));
    NSLog(@"%@", NSStringFromCGRect(v.bounds));
}

ผลลัพธ์ของรหัสนี้คือ:

การวางแนวของอุปกรณ์เคสคือแนวตั้ง

{{0, 0}, {768, 1024}}
{{0, 0}, {768, 1024}}

การวางแนวของอุปกรณ์เคสคือแนวนอน

{{0, 0}, {768, 1024}}
{{0, 0}, {1024, 768}}

เห็นได้ชัดว่าคุณสามารถเห็นความแตกต่างระหว่างกรอบและขอบเขต


2
นี่ไม่ใช่ความจริงอีกต่อไป (iOS 8)
Julian Król


13

กรอบเป็นรูปสี่เหลี่ยมผืนผ้าที่กำหนด UIView ด้วยความเคารพต่อ SuperView

ขอบเขตดูแลรักษาเป็นช่วงของค่าที่กำหนดว่าNSView เป็นระบบพิกัด

คือทุกอย่างในสี่เหลี่ยมนี้จะแสดงใน UIView


10

frameคือจุดเริ่มต้น (มุมบนซ้าย) และขนาดของมุมมองในระบบพิกัดของมุมมอง super ซึ่งหมายความว่าคุณแปลมุมมองในมุมมอง super โดยการเปลี่ยนต้นกำเนิดของเฟรมขอบเขตในทางกลับกันคือขนาดและต้นกำเนิดใน ระบบพิกัดของตัวเองดังนั้นโดยค่าเริ่มต้นขอบเขตที่มาคือ (0,0)

เวลาส่วนใหญ่ของกรอบและขอบเขตจะสอดคล้องกัน แต่ถ้าคุณมีมุมมองของเฟรม ((140,65), (200,250)) และขอบเขต ((0,0), (200,250)) และมุมมองเอียง เพื่อให้มันยืนที่มุมขวาล่างจากนั้นขอบเขตจะยังคงอยู่ ((0,0), (200,250)) แต่เฟรมไม่ได้

ป้อนคำอธิบายรูปภาพที่นี่

เฟรมจะเป็นสี่เหลี่ยมที่เล็กที่สุดที่ห่อหุ้ม / ล้อมรอบมุมมองดังนั้นเฟรม (ดังในรูปภาพ) จะเป็น (140,65), (320,320))

ข้อแตกต่างอีกอย่างคือถ้าคุณมี superView ที่มีขอบเขต ((0,0), (200,200)) และ superView นี้มี subView ที่มีเฟรมคือ ((20,20), (100,100)) และคุณเปลี่ยนขอบเขต superView ถึง ((20,20), (200,200)) จากนั้นเฟรมย่อยจะยังคง ((20,20), (100,100)) แต่ชดเชยด้วย (20,20) เพราะระบบพิกัดของผู้ประสานงานถูกชดเชยด้วย (20, 20)

ฉันหวังว่านี่จะช่วยให้ใครบางคน


เกี่ยวกับย่อหน้าสุดท้าย: กรอบจะสัมพันธ์กับมันsubView superViewเปลี่ยนsuperViewขอบเขตเพื่ออะไรจะไม่ให้ตรงกับต้นกำเนิดของมันsubView superView
staticVoidMan

5

จัดวางเฟรมสัมพันธ์กับ SuperView ในขณะที่ขอบเขตสัมพันธ์กับ NSView

ตัวอย่าง: X = 40, Y = 60.Also มี 3 Views.This แผนภาพแสดงความคิดที่ชัดเจน

FRAME

BOUNDS


4

ให้ฉันเพิ่ม 5 เซนต์ของฉัน

กรอบถูกใช้โดยมุมมองพาเรนต์ของมุมมองเพื่อวางไว้ในมุมมองพาเรนต์

ขอบเขตจะถูกใช้โดยมุมมองเพื่อวางเนื้อหาของตัวเอง (เช่นมุมมองการเลื่อนในขณะที่เลื่อน) ดูเพิ่มเติมคลิปไปที่ขอบเขต ขอบเขตยังสามารถใช้เพื่อซูมเข้า / ออกเนื้อหาของมุมมอง

ความคล้ายคลึง:
กรอบ ~ หน้าจอทีวี
ขอบเขต ~ กล้อง (ซูมย้ายหมุน)


2

คำตอบข้างต้นอธิบายความแตกต่างระหว่างขอบเขตและเฟรมได้ดีมาก

ขอบเขต: มุมมองขนาดและตำแหน่งตามระบบพิกัดของตัวเอง

กรอบ: ขนาดมุมมองและตำแหน่งสัมพันธ์กับ SuperView

จากนั้นมีความสับสนว่าในกรณีของขอบเขต X, Y จะเป็น "0" เสมอ นี้ไม่เป็นความจริง สิ่งนี้สามารถเข้าใจได้ใน UIScrollView และ UICollectionView เช่นกัน

เมื่อขอบเขต 'x, y ไม่ใช่ 0
ลองสมมุติว่าเรามี UIScrollView เราได้ดำเนินการให้เลขหน้า UIScrollView มี 3 หน้าและความกว้างของ ContentSize คือสามเท่าของความกว้างหน้าจอ (สมมติว่า ScreenWidth คือ 320) ความสูงนั้นคงที่ (สมมติ 200)

scrollView.contentSize = CGSize(x:320*3, y : 200)

เพิ่ม UIImageViews สามรายการเป็นมุมมองย่อยและดูค่าxของเฟรมอย่างใกล้ชิด

let imageView0 = UIImageView.init(frame: CGRect(x:0, y: 0 , width : scrollView.frame.size.width, height : scrollView.frame.size.height))
let imageView1 :  UIImageView.init( frame: CGRect(x:320, y: 0 , width : scrollView.frame.size.width, height : scrollView.frame.size.height))
let imageView2 :  UIImageView.init(frame: CGRect(x:640, y: 0 , width : scrollView.frame.size.width, height : scrollView.frame.size.height))
scrollView.addSubview(imageView0)
scrollView.addSubview(imageView0)
scrollView.addSubview(imageView0)
  1. หน้า 0: เมื่อ ScrollView เป็น 0 หน้าขอบเขตจะเป็น (x: 0, y: 0, ความกว้าง: 320, ความสูง: 200)

  2. หน้า 1: เลื่อนและย้ายไปที่หน้า 1.
    ตอนนี้ขอบเขตจะเป็น(x: 320, y: 0, ความกว้าง: 320, ความสูง: 200) จำไว้ว่าเราพูดด้วยความเคารพต่อระบบพิกัดของมันเอง ดังนั้นตอนนี้ "ส่วนที่มองเห็นได้" ของ ScrollView ของเรามี "x" ที่ 320 ดูที่เฟรมของ imageView1

  3. หน้า 2: เลื่อนและย้ายไปที่หน้า 2 ขอบเขต: (x: 640, y: 0, ความกว้าง: 320, ความสูง: 200) ดูที่เฟรมของภาพอีกครั้ง 2

เช่นเดียวกับกรณีของ UICollectionView วิธีที่ง่ายที่สุดในการดูคอลเล็กชัน View คือการเลื่อนและพิมพ์ / บันทึกขอบเขตและคุณจะได้รับแนวคิด


2

คำตอบทั้งหมดข้างต้นถูกต้องและนี่คือสิ่งที่ฉันทำในสิ่งนี้:

หากต้องการแยกความแตกต่างระหว่างเฟรมและขอบเขต CONCEPTS ผู้พัฒนาควรอ่าน:

  1. สัมพันธ์กับ superview (มุมมองพาเรนต์หนึ่งรายการ) ซึ่งอยู่ภายใน = FRAME
  2. สัมพันธ์กับระบบพิกัดของตัวเองกำหนดตำแหน่งย่อย = BOUNDS

"ขอบเขต" ทำให้เกิดความสับสนเนื่องจากให้การแสดงผลว่าพิกัดเป็นตำแหน่งของมุมมองที่ตั้งค่าไว้ แต่สิ่งเหล่านี้อยู่ในความสัมพันธ์และปรับเปลี่ยนตามค่าคงที่ของเฟรม

หน้าจอ iPhone


1

อีกหนึ่งภาพประกอบเพื่อแสดงความแตกต่างระหว่างกรอบและขอบเขต ในตัวอย่างนี้:

  • View B เป็นมุมมองย่อยของ View A
  • View B ถูกย้ายไปที่ x:60, y: 20
  • View B ถูกหมุน 45 degrees

ป้อนคำอธิบายรูปภาพที่นี่


0

กรอบเทียบกับที่ถูกผูกไว้

  • หากคุณสร้างมุมมองที่ X: 0, Y: 0, ความกว้าง: 400, ความสูง: 400 กรอบและขอบเขตของมันจะเหมือนกัน
  • หากคุณเลื่อนมุมมองนั้นไปที่ X: 400 เฟรมนั้นจะสะท้อนการเปลี่ยนแปลงนั้น แต่ขอบเขตจะไม่ โปรดจำไว้ว่าขอบเขตนั้นสัมพันธ์กับพื้นที่ของมุมมองและภายในไม่มีอะไรเปลี่ยนแปลง
  • หากคุณแปลงมุมมองเช่นหมุนหรือปรับขนาดกรอบจะเปลี่ยนเพื่อสะท้อนให้เห็น แต่ขอบเขตยังไม่ดีเท่าที่มุมมองเกี่ยวข้องภายในก็ไม่เปลี่ยน
  • หากคุณเปลี่ยนขอบเขตแล้วมันจะเปลี่ยนเนื้อหาภายในเฟรมเนื่องจากต้นกำเนิดของขอบเขตสี่เหลี่ยมผืนผ้าเริ่มต้นที่ส่วนอื่นของมุมมอง

-1

frame = ตำแหน่งและขนาดของมุมมองโดยใช้ระบบพิกัดของมุมมองพาเรนต์

bounds = ตำแหน่งและขนาดของมุมมองโดยใช้ระบบพิกัดของตัวเอง

มุมมองจะติดตามขนาดและตำแหน่งโดยใช้สองรูปสี่เหลี่ยมผืนผ้า: กรอบรูปสี่เหลี่ยมผืนผ้าและรูปสี่เหลี่ยมผืนผ้าขอบเขต กรอบสี่เหลี่ยมกำหนดตำแหน่งและขนาดของมุมมองใน superview โดยใช้ระบบพิกัดของ superview ขอบเขตขอบเขตกำหนดระบบพิกัดภายในที่ใช้เมื่อวาดเนื้อหาของมุมมองรวมถึงที่มาและการปรับสเกล รูปที่ 2-1 แสดงให้เห็นถึงความสัมพันธ์ระหว่างกรอบสี่เหลี่ยมทางด้านซ้ายและขอบด้านขวาทางด้านขวา”

กล่าวโดยสรุปเฟรมคือแนวคิดของมุมมองของ superview และขอบเขตคือแนวคิดของมุมมอง การมีหลายระบบการประสานงานระบบหนึ่งสำหรับแต่ละมุมมองเป็นส่วนหนึ่งของลำดับชั้นมุมมอง


รูป 2-1 อยู่ที่ไหน
Alexander Mayatsky
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.