เปลี่ยนระยะขอบด้านขวาของมุมมองโดยทางโปรแกรมหรือไม่


172

สามารถเปลี่ยนคุณลักษณะนี้แบบไดนามิกในรหัส Java หรือไม่?

android:layout_marginRight

ฉันมีTextViewที่จะต้องเปลี่ยนตำแหน่งของมันบางพิกเซลไปทางซ้ายแบบไดนามิก

จะทำอย่างไรกับทางโปรแกรม

คำตอบ:


462

แก้ไข: วิธีทั่วไปมากขึ้นของการทำเช่นนี้ที่ไม่ขึ้นอยู่กับประเภทรูปแบบ (นอกเหนือจากนั้นเป็นประเภทรูปแบบที่รองรับระยะขอบ):

public static void setMargins (View v, int l, int t, int r, int b) {
    if (v.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
        ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
        p.setMargins(l, t, r, b);
        v.requestLayout();
    }
}

คุณควรตรวจสอบเอกสารสำหรับTextView โดยทั่วไปคุณจะต้องได้รับวัตถุ LayoutParams ของ TextView และแก้ไขระยะขอบจากนั้นตั้งค่ากลับเป็น TextView สมมติว่ามันอยู่ใน LinearLayout ลองอะไรเช่นนี้:

TextView tv = (TextView)findViewById(R.id.my_text_view);
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)tv.getLayoutParams();
params.setMargins(0, 0, 10, 0); //substitute parameters for left, top, right, bottom
tv.setLayoutParams(params);

ฉันไม่สามารถทดสอบได้ในตอนนี้ดังนั้นการคัดเลือกนักแสดงของฉันอาจถูกปิดไปเล็กน้อย แต่ LayoutParams เป็นสิ่งที่จำเป็นต้องแก้ไขเพื่อเปลี่ยนระยะขอบ

บันทึก

อย่าลืมว่าหาก TextView ของคุณอยู่ภายในเช่น RelativeLayoutคุณควรใช้RelativeLayout.LayoutParamsแทน LinearLayout.LayoutParams


39
เพียงอธิบายรายละเอียดของคุณในกรณีที่คนอื่นกำลังมองหาสิ่งนี้ หากคุณกำลังสร้าง TextView โดยทางโปรแกรมคุณจะต้องสร้างวัตถุ LinearLayout.LayoutParams ใหม่ด้วยแทนที่จะพยายามดึงออกมาทาง. getLayoutParams ();
Ares

มันใช้งานได้ดีและดูเหมือนว่ามันจะตั้งค่าระยะขอบเป็นพิกเซล เป็นไปได้ไหมที่จะตั้งเป็น dp?
SirRupertIII

3
@KKendall: เพียงแปลง DP ของคุณเป็น PXก่อน
Kevin Coppock

ตามหมายเหตุของคุณ: ฉันมีข้อสงสัย หากมุมมองข้อความหรือปุ่มอยู่ภายในแถวของตาราง ถ้าอย่างนั้นฉันควรจะใช้สิ่งใดแทนเค้าโครงสัมพัทธ์, เค้าโครงตาราง?
tejas

1
ที่เกี่ยวข้องกับบันทึกย่อคุณสามารถส่ง tv.getLayoutParams () ไปยัง ViewGroup.MarginLayoutParams ด้วยวิธีนี้มันไม่สำคัญว่าเค้าโครงจะเป็นแบบไหนตราบใดที่มันใช้ระยะขอบ
Radu Simionescu

17

ใช้ LayoutParams (ตามที่อธิบายแล้ว) อย่างไรก็ตามต้องระวังว่า LayoutParams ใดให้เลือก ตามhttps://stackoverflow.com/a/11971553/3184778 "คุณต้องใช้รายการที่เกี่ยวข้องกับ PARENT ของมุมมองที่คุณกำลังทำงานไม่ใช่มุมมองจริง"

ถ้าเช่น TextView นั้นอยู่ใน TableRow คุณต้องใช้ TableRow.LayoutParams แทน RelativeLayout หรือ LinearLayout


ขอบคุณสำหรับการชี้แจง!
Scott Biggs

1
มันแย่จริง ๆ ที่คุณต้องรู้ว่าปลายทางของกล่องข้อความเพื่อกำหนดระยะขอบ ... คุณคิดว่าจะมีทางออกที่เป็นปลายทางที่เป็นอิสระ
TatiOverflow

10

ใช้ฟังก์ชันนี้เพื่อตั้งค่าระยะขอบทุกประเภท

      public void setViewMargins(Context con, ViewGroup.LayoutParams params,      
       int left, int top , int right, int bottom, View view) {

    final float scale = con.getResources().getDisplayMetrics().density;
    // convert the DP into pixel
    int pixel_left = (int) (left * scale + 0.5f);
    int pixel_top = (int) (top * scale + 0.5f);
    int pixel_right = (int) (right * scale + 0.5f);
    int pixel_bottom = (int) (bottom * scale + 0.5f);

    ViewGroup.MarginLayoutParams s = (ViewGroup.MarginLayoutParams) params;
    s.setMargins(pixel_left, pixel_top, pixel_right, pixel_bottom);

    view.setLayoutParams(params);
}

2
ทำไมต้องเพิ่ม 0.5f?
behelit

2
@behelit ฉันรู้ว่ามันสาย แต่สำหรับใครที่กำลังมองหา ... เมื่อคุณเหวี่ยงทุ่นไปที่ int การลอยรอบ 0.0 -> 0.4 รอบถึง 0 ในขณะที่ 0.5 -> 0.9 รอบต่อ 1 ซึ่งสามารถสร้างความไม่สอดคล้องกันใน ints สุดท้าย เพื่อป้องกันสิ่งนี้การเพิ่ม 0.5 ทำให้การปัดเศษทั้งหมดเป็น 1 ทำไม? สมมติว่าโฟลตของคุณคือ 0.3: 0.3 + 0.5 = 0.8 ซึ่งปัดได้สูงสุด 1 สมมติว่าโฟลตของคุณคือ 0.8: 0.8 + 0.5 = 1.3 ซึ่งปัดลงไปจนถึง 1 คุณสามารถปลอดภัยในการรู้รอบการรอบสุดท้าย (หมายเหตุด้านข้าง: เราเพิ่ม 0.5 แทนการลบเพื่อหลีกเลี่ยงการได้รับผลลบ)
Psest328

7

อัปเดต: Android KTX

โมดูลหลัก KTXให้ส่วนขยายสำหรับห้องสมุดทั่วไปที่เป็นส่วนหนึ่งของกรอบ Android, androidx.core.viewในหมู่พวกเขา

dependencies {
    implementation "androidx.core:core-ktx:{latest-version}"
}

ฟังก์ชันส่วนขยายต่อไปนี้สะดวกต่อการจัดการกับระยะขอบ:

  • setMargins() ฟังก์ชั่นการขยาย:

ชุดขอบของแกนทั้งหมดใน'sViewGroup MarginLayoutParams(ต้องระบุมิติเป็นพิกเซลดูส่วนสุดท้ายหากคุณต้องการทำงานกับ dp)

inline fun MarginLayoutParams.setMargins(@Px size: Int): Unit
// E.g. 16px margins
val params = (myView.layoutParams as ViewGroup.MarginLayoutParams)
params.setMargins(16)

ปรับปรุงอัตรากำไรขั้นต้นใน'sViewGroupViewGroup.MarginLayoutParams

inline fun MarginLayoutParams.updateMargins(
    @Px left: Int = leftMargin, 
    @Px top: Int = topMargin, 
    @Px right: Int = rightMargin, 
    @Px bottom: Int = bottomMargin
): Unit
// Example: 8px left margin 
params.updateMargins(left = 8)

อัปเดตระยะขอบสัมพัทธ์ในViewGroup's MarginLayoutParams(เริ่ม / สิ้นสุดแทนซ้าย / ขวา)

inline fun MarginLayoutParams.updateMarginsRelative(
    @Px start: Int = marginStart, 
    @Px top: Int = topMargin, 
    @Px end: Int = marginEnd, 
    @Px bottom: Int = bottomMargin
): Unit
// E.g: 8px start margin 
params.updateMargins(start = 8)

คุณสมบัติส่วนขยายต่อไปนี้สะดวกสำหรับการรับระยะขอบปัจจุบัน:

inline val View.marginBottom: Int
inline val View.marginEnd: Int
inline val View.marginLeft: Int
inline val View.marginRight: Int
inline val View.marginStart: Int
inline val View.marginTop: Int
// E.g: get margin bottom
val bottomPx = myView1.marginBottom
  • ใช้dpแทนpx:

หากคุณต้องการทำงานกับdp(พิกเซลแบบหนาแน่น) แทนคุณpxจะต้องแปลงก่อน คุณสามารถทำได้อย่างง่ายดายด้วยคุณสมบัติส่วนขยายต่อไปนี้:

val Int.px: Int
    get() = (this * Resources.getSystem().displayMetrics.density).toInt()

จากนั้นคุณสามารถเรียกใช้ฟังก์ชันส่วนขยายก่อนหน้าเช่น:

params.updateMargins(start = 16.px, end = 16.px, top = 8.px, bottom = 8.px)
val bottomDp = myView1.marginBottom.dp

คำตอบเก่า:

ใน Kotlin คุณสามารถประกาศฟังก์ชันส่วนขยายเช่น:

fun View.setMargins(
    leftMarginDp: Int? = null,
    topMarginDp: Int? = null,
    rightMarginDp: Int? = null,
    bottomMarginDp: Int? = null
) {
    if (layoutParams is ViewGroup.MarginLayoutParams) {
        val params = layoutParams as ViewGroup.MarginLayoutParams
        leftMarginDp?.run { params.leftMargin = this.dpToPx(context) }
        topMarginDp?.run { params.topMargin = this.dpToPx(context) }
        rightMarginDp?.run { params.rightMargin = this.dpToPx(context) }
        bottomMarginDp?.run { params.bottomMargin = this.dpToPx(context) }
        requestLayout()
    }
}

fun Int.dpToPx(context: Context): Int {
    val metrics = context.resources.displayMetrics
    return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), metrics).toInt()
}

จากนั้นคุณสามารถเรียกมันว่า:

myView1.setMargins(8, 16, 34, 42)

หรือ:

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