ฉันจะกำหนดตำแหน่งมุมมองแบบไดนามิกใน Android ได้อย่างไร


102

ฉันจะเปลี่ยนตำแหน่งการดูผ่านโค้ดได้อย่างไร เช่นเดียวกับการเปลี่ยนตำแหน่ง X, Y เป็นไปได้ไหม?

คำตอบ:


117

สำหรับอะไรด้านล่างรังผึ้ง (API ระดับ 11) setLayoutParams(...)คุณจะต้องใช้

หากคุณสามารถ จำกัด การสนับสนุนของคุณเพื่อรังผึ้งขึ้นคุณสามารถใช้setX(...), setY(...), setLeft(...), setTop(...)ฯลฯ


41
จากเอกสารของ setTop () developer.android.com/reference/android/view/… : sets the top position of this view relative to its parent. This method is meant to be called by the layout system and should not generally be called otherwise, because the property may be changed at any time by the layout.- นั่นอาจจะไม่ใช่ความคิดที่ดีนัก;)
katzenhut

47

ได้คุณสามารถกำหนดตำแหน่งการมองเห็นแบบไดนามิกใน Android ได้ ในทำนองเดียวกันคุณมีImageViewในLinearLayoutของ XML ของคุณ file.So คุณสามารถกำหนดตำแหน่งผ่านLayoutParams.But ให้แน่ใจว่าจะใช้LayoutParamsตามรูปแบบการดำเนินการใน XML ของคุณ file.There จะแตกต่างกันLayoutParamsตามรูปแบบที่นำมา

นี่คือรหัสที่จะตั้ง:

    LayoutParams layoutParams=new LayoutParams(int width, int height);
    layoutParams.setMargins(int left, int top, int right, int bottom);
    imageView.setLayoutParams(layoutParams);

ฉันหวังว่าจะเป็นประโยชน์กับคุณในการกำหนดตำแหน่ง


15
โปรดทราบว่าคุณต้องนำเข้า android.widget.LinearLayout.LayoutParams; เนื่องจากค่าเริ่มต้นคือ LayoutParams ของ ViewGroup
David T.

ดูเหมือนว่าสิ่งนี้จะไม่ทำงานบน Android 8+ คุณประสบปัญหาที่คล้ายกันหรือไม่?
MyFlashLab

มีความคิดว่าทำไมนักออกแบบ Andriod ถึงประสบปัญหาดังกล่าวเพื่อป้องกันไม่ให้ progammers ใช้ X, Y เพื่อวางตำแหน่งสิ่งต่างๆ ในที่สุดทุกอย่างจะต้องถูกวาดให้เป็นแบบนั้น สิ่งนี้แสดงให้เห็นว่า Android ได้รับการออกแบบโดยผู้ที่ไม่สามารถเขียนโค้ดได้
Paul McCarthy

34

มีคำตอบที่ถูกต้องแตกต่างกันอยู่แล้ว แต่ดูเหมือนจะไม่มีคำตอบที่ถูกต้องว่าจะใช้วิธีใดในกรณีใดยกเว้นข้อ จำกัด ระดับ API ที่เกี่ยวข้อง:

  • หากคุณสามารถรอรอบเค้าโครงและกลุ่มมุมมองหลักสนับสนุนMarginLayoutParams(หรือคลาสย่อย) ให้ตั้งค่าmarginLeft/ marginTopตามนั้น

  • หากคุณต้องการเปลี่ยนตำแหน่งทันทีและอย่างต่อเนื่อง (เช่นสำหรับจุดยึด PopupMenu) ให้เรียกlayout(l, t, r, b)ใช้พิกัดเดียวกันเพิ่มเติม สิ่งนี้มีไว้ล่วงหน้าว่าระบบเค้าโครงจะยืนยันอะไรในภายหลัง

  • สำหรับการเปลี่ยนแปลงทันที (ชั่วคราว) (เช่นภาพเคลื่อนไหว) ให้ใช้setX()/ setY()แทน ในกรณีที่ขนาดหลักไม่ขึ้นอยู่กับ WRAP_CHILDREN อาจใช้ได้ดีในการใช้setX()/ setY()เฉพาะ

  • ห้ามใช้setLeft()/ setRight()/ setBottom()/ setTop()ดูด้านล่าง

พื้นหลัง : ช่องmLeft/ mTop/ mBottom/ mRightจะถูกเติมจาก LayoutParams ที่สอดคล้องกันในเค้าโครง () เค้าโครงเรียกโดยนัยและแบบอะซิงโครนัสโดยระบบเค้าโครงมุมมองของ Android ดังนั้นการตั้งค่าMarginLayoutParamsดูเหมือนจะเป็นวิธีที่ปลอดภัยและสะอาดที่สุดในการกำหนดตำแหน่งอย่างถาวร อย่างไรก็ตามความล่าช้าของเลย์เอาต์แบบอะซิงโครนัสอาจมีปัญหาในบางกรณีเช่นเมื่อใช้มุมมองเพื่อแสดงเคอร์เซอร์และควรจะวางตำแหน่งใหม่และทำหน้าที่เป็นจุดยึด PopupMenu ในเวลาเดียวกัน ในกรณีนี้โทรlayout()งานได้ดีสำหรับฉัน

ปัญหาเกี่ยวกับsetLeft()และsetTop()คือ:

  • การเรียกพวกเขาเพียงอย่างเดียวนั้นไม่เพียงพอคุณต้องโทรsetRight()และsetBottom()เพื่อหลีกเลี่ยงการยืดหรือหดมุมมอง

  • การใช้งานวิธีการเหล่านี้ดูค่อนข้างซับซ้อน (= ทำงานบางอย่างเพื่อพิจารณาการเปลี่ยนแปลงขนาดมุมมองที่เกิดจากแต่ละวิธี)

  • ดูเหมือนว่าจะทำให้เกิดปัญหาแปลก ๆ กับช่องป้อนข้อมูล: แป้นพิมพ์ตัวเลขแบบนุ่ม EditText บางครั้งไม่อนุญาตให้ใช้ตัวเลข

setX()และsetY()ทำงานนอกระบบเค้าโครงและค่าที่เกี่ยวข้องจะถือว่าเป็นค่าชดเชยเพิ่มเติมสำหรับค่าซ้าย / บน / ล่าง / ขวาที่กำหนดโดยระบบเค้าโครงโดยจะเปลี่ยนมุมมองตามนั้น ดูเหมือนว่าจะถูกเพิ่มสำหรับภาพเคลื่อนไหว (ซึ่งจำเป็นต้องมีเอฟเฟกต์ทันทีโดยไม่ต้องผ่านวงจรเลย์เอาต์)


สวัสดีสเตฟาน คุณช่วยแนะนำหนังสือหรือบทความบางส่วนที่ฉันสามารถเข้าใจว่าระบบเค้าโครง Android ทำงานอย่างไร ฉันเข้าใจลำดับของการเรียกใช้ layout () onMeasure () onDraw () แต่ต้องการทราบรายละเอียดเพิ่มเติม ขอบคุณล่วงหน้า
Sergey Brazhnik

น่าเสียดายที่ฉันทำไม่ได้ - การอ้างอิงที่ดีที่สุดและชัดเจนที่สุดดูเหมือนจะเป็นซอร์สโค้ด Android ที่แท้จริง O :)
Stefan Haustein

ฉันใช้ setY เพื่อเปลี่ยนมุมมองมันเปลี่ยนในรอบเค้าโครงถัดไปไม่ใช่ทันที?
สัญญาณ

คุณกำหนดสิ่งนี้ได้อย่างไร?
Stefan Haustein

มันคุ้มค่าที่จะชี้ให้เห็นว่าmarginLeftสามารถตั้งค่าได้โดยใช้setLayoutParamsกับnew FrameLayout.LayoutParams(width, height)ที่คุณตั้งค่าmarginLeft
lucidbrot

18

มีไลบรารีชื่อNineOldAndroidsซึ่งช่วยให้คุณใช้ไลบรารีแอนิเมชั่น Honeycomb ได้จนถึงเวอร์ชันหนึ่ง

ซึ่งหมายความว่าคุณสามารถกำหนดด้านซ้าย, ขวา, การแปล X / Y ด้วยอินเทอร์เฟซที่แตกต่างกันเล็กน้อย

นี่คือวิธีการทำงาน:

ViewHelper.setTranslationX(view, 50f);

คุณเพียงแค่ใช้วิธีการแบบคงที่จากคลาส ViewHelper ส่งผ่านมุมมองและค่าที่คุณต้องการตั้งค่า


16

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


13

คุณสามารถลองใช้วิธีการต่อไปนี้หากคุณใช้ HoneyComb Sdk (API ระดับ 11)

view.setX(float x);

พารามิเตอร์ x คือตำแหน่งภาพ x ของมุมมองนี้

view.setY(float y);

พารามิเตอร์ y คือตำแหน่งภาพ y ของมุมมองนี้

ฉันหวังว่ามันจะเป็นประโยชน์กับคุณ :)


4
ฉันกำลังทำงานกับ 2.2 Froyo และวิธีการเหล่านี้ไม่มีอยู่ในนั้น
Arun Badole

7

สำหรับการรองรับ API ทุกระดับคุณสามารถใช้ได้ดังนี้:

ViewPropertyAnimator.animate(view).translationYBy(-yourY).translationXBy(-yourX).setDuration(0);

เพราะเขาต้องการเปลี่ยนตำแหน่งและวิธีแก้ปัญหาด้านบนจะดีกว่าและไม่ต้องการภาพเคลื่อนไหว
FireZenk

นอกจากนี้การแปลอาจทำให้การดูไป (บางส่วน) นอกจอ
mewa

4

กำหนดตำแหน่งทางซ้ายของมุมมองนี้โดยสัมพันธ์กับระดับบนสุด:

view.setLeft(int leftPosition);

กำหนดตำแหน่งที่ถูกต้องของมุมมองนี้โดยสัมพันธ์กับระดับบนสุด:

view.setRight(int rightPosition);

กำหนดตำแหน่งบนสุดของมุมมองนี้โดยสัมพันธ์กับระดับบนสุด:

view.setTop(int topPosition);

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

view.setBottom(int bottomPositon);

วิธีการข้างต้นใช้เพื่อกำหนดตำแหน่งมุมมองที่เกี่ยวข้องกับระดับบนสุด


ขออภัยไม่มีวิธีการเหล่านี้คุณสามารถส่งรหัสให้ฉันได้ไหม
Arun Badole

4
"วิธีนี้ถูกเรียกโดยระบบเค้าโครงและโดยทั่วไปไม่ควรเรียกเป็นอย่างอื่นเพราะเค้าโครงอาจเปลี่ยนแปลงได้ตลอดเวลา"
GDanger

4

ใช้ LayoutParams หากคุณใช้ LinearLayout คุณต้องนำเข้า android.widget.LinearLayout.LayoutParams มิฉะนั้นจะนำเข้า LayoutParams เวอร์ชันที่เหมาะสมสำหรับเลย์เอาต์ที่คุณใช้ไม่เช่นนั้นจะทำให้เกิดClassCastExceptionจากนั้น:

LayoutParams layoutParams = new LayoutParams(int width, int height);
layoutParams.setMargins(int left, int top, int right, int bottom);
imageView.setLayoutParams(layoutParams);

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


แล้วเราจะย้ายมุมมองไปยังตำแหน่งที่ต้องการโดยไม่ส่งผลกระทบต่อมุมมองเดิมได้อย่างไร
เจมส์

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

3

ใช้RelativeLayoutวางมุมมองของคุณรับRelativeLayout.LayoutParamsวัตถุจากมุมมองของคุณและกำหนดระยะขอบตามที่คุณต้องการ จากนั้นเรียกrequestLayout()ดูมุมมองของคุณ นี่เป็นวิธีเดียวที่ฉันรู้


1

ฉันพบว่า @Stefan Haustein ใกล้เคียงกับประสบการณ์ของฉันมาก แต่ไม่แน่ใจ 100% คำแนะนำของฉันคือ:

  • setLeft()/ setRight()/ setBottom()/ ใช้setTop()ไม่ได้ในบางครั้ง
  • หากคุณต้องการที่จะตั้งตำแหน่งชั่วคราว (เช่นสำหรับการทำภาพเคลื่อนไหวไม่ได้รับผลกระทบลำดับชั้นหนึ่ง)เมื่อมุมมองที่ถูกเพิ่มและแสดงให้เห็นเพียงแค่การใช้งานsetX()/setY()แทน (คุณอาจต้องการค้นหาเพิ่มเติมในความแตกต่างsetLeft()และsetX() )
  • และโปรดทราบว่า X, Y ดูเหมือนจะเป็นค่าสัมบูรณ์และได้รับการสนับสนุนโดย AbsoluteLayout ซึ่งตอนนี้เลิกใช้แล้ว ดังนั้นคุณรู้สึกว่า X, Y น่าจะไม่ได้รับการสนับสนุนอีกต่อไป และใช่มันเป็นเพียงบางส่วนเท่านั้น มันหมายความว่าถ้าคุณมุมมองเพิ่ม setX () Sety () จะทำงานได้อย่างสมบูรณ์ ; มิฉะนั้นเมื่อคุณพยายามเพิ่มมุมมองในมุมมองเค้าโครงกลุ่ม (เช่น FrameLayout, LinearLayout, RelativeLayout) คุณต้องตั้งค่า LayoutParams ด้วยmarginLeft, marginTopแทน (setX (), setY () ในกรณีนี้จะใช้ไม่ได้ในบางครั้ง)
  • ตั้งตำแหน่งของมุมมองโดย marginLeft และ marginTopเป็นหมู่กระบวนการ ดังนั้นจึงต้องใช้เวลาเล็กน้อยในการลำดับชั้นของการปรับปรุง หากคุณใช้มุมมองทันทีหลังจากที่อัตรากำไรขั้นต้นชุดมันคุณอาจได้รับค่าที่ไม่ถูกต้อง

0

สิ่งหนึ่งที่ควรคำนึงถึงในการวางตำแหน่งก็คือแต่ละมุมมองมีดัชนีที่สัมพันธ์กับมุมมองระดับบนสุด ดังนั้นหากคุณมีเค้าโครงเชิงเส้นที่มีมุมมองย่อยสามมุมมองย่อยแต่ละมุมมองจะมีดัชนี: 0, 1, 2 ในกรณีข้างต้น

สิ่งนี้ช่วยให้คุณสามารถเพิ่มมุมมองไปยังตำแหน่งสุดท้าย (หรือจุดสิ้นสุด) ในมุมมองระดับบนสุดโดยทำสิ่งนี้:

int childCount = parent.getChildCount();
parentView.addView(newView, childCount);

หรือคุณสามารถแทนที่มุมมองโดยใช้สิ่งต่อไปนี้:

int childIndex = parentView.indexOfChild(childView);
childView.setVisibility(View.GONE);

parentView.addView(newView, childIndex);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.