ไลบรารีการออกแบบของ Android - ปัญหาการขยายปุ่มการดำเนินการแบบลอยตัว / ระยะขอบ


109

ฉันใช้ FloatingActionButton ใหม่จากไลบรารีการออกแบบของ Google และพบปัญหาช่องว่าง / ระยะขอบแปลก ๆ รูปภาพนี้ (เปิดตัวเลือกเค้าโครงของนักพัฒนา) มาจาก API 22

ใส่คำอธิบายภาพที่นี่

และจาก API 17

ใส่คำอธิบายภาพที่นี่

นี่คือ XML

<android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:layout_gravity="bottom|right"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="20dp"
        android:layout_marginTop="-32dp"
        android:src="@drawable/ic_action_add"
        app:fabSize="normal"
        app:elevation="4dp"
        app:borderWidth="0dp"
        android:layout_below="@+id/header"/>

เหตุใด FAB ใน API 17 จึงมีช่องว่าง / ระยะขอบที่ใหญ่กว่ามาก


1
ฉันขอแนะนำให้ใช้CoordinatorLayoutเพื่อจัดแนวในแนวตั้งและวางลูกตาให้เป็นพิเศษก่อนอมยิ้ม คุณอาจจะคิดออกจากแหล่ง FAB decompiled แต่ฉันอยากจะรอสำหรับ Google CardViewที่จะแก้ไขได้เหมือนพวกเขาได้สำหรับ
DariusL

คำตอบ:


129

ปรับปรุง (ต.ค. 2559):

วิธีแก้ไขที่ถูกต้องคือใส่app:useCompatPadding="true"ลงใน FloatingActionButton ของคุณ สิ่งนี้จะทำให้ช่องว่างภายในสอดคล้องกันระหว่างเวอร์ชัน API ต่างๆ อย่างไรก็ตามสิ่งนี้ดูเหมือนว่าจะทำให้ระยะขอบเริ่มต้นปิดลงเล็กน้อยดังนั้นคุณอาจต้องปรับเปลี่ยน แต่อย่างน้อยก็ไม่จำเป็นต้องมีสไตล์เฉพาะ API อีกต่อไป

คำตอบก่อนหน้า:

คุณสามารถทำได้อย่างง่ายดายโดยใช้รูปแบบเฉพาะ API ตามปกติของคุณvalues/styles.xmlให้ใส่สิ่งนี้:

<style name="floating_action_button">
    <item name="android:layout_marginLeft">0dp</item>
    <item name="android:layout_marginTop">0dp</item>
    <item name="android:layout_marginRight">8dp</item>
    <item name="android:layout_marginBottom">0dp</item>
</style>

จากนั้นภายใต้ values-v21 / styles.xml ให้ใช้สิ่งนี้:

<style name="floating_action_button">
    <item name="android:layout_margin">16dp</item>
</style>

และใช้สไตล์กับปุ่ม FloatingActionButton ของคุณ:

<android.support.design.widget.FloatingActionButton
...
style="@style/floating_action_button"
...
/>

ดังที่คนอื่น ๆ ได้กล่าวไว้ใน API <20 ปุ่มจะแสดงเงาของตัวเองซึ่งจะเพิ่มความกว้างเชิงตรรกะโดยรวมของมุมมองในขณะที่ใน API> = 20 จะใช้พารามิเตอร์ระดับความสูงใหม่ซึ่งไม่ได้มีส่วนช่วยในการดูความกว้าง


19
buggy Android .. :(
Abdullah Shoaib

3
ดูน่าเกลียดน่าขัน แต่ดูเหมือนว่าจะไม่มีทางแก้ไขอื่นใด
11

3
คำตอบที่ดีขอบคุณ ฉันขอแนะนำให้แก้ไขและเพิ่มสไตล์สำหรับแท็บเล็ตได้ไหม สำหรับ API> = 20 ระยะขอบคือ 24dp; สำหรับ API <20 ผมสังเกตเห็นว่าที่คุณต้องการ<ชื่อรายการ = "หุ่นยนต์: layout_marginRight"> 12dp </ รายการ> <ชื่อรายการ = "หุ่นยนต์: layout_marginBottom"> 6dp </ item> ฉันต้องคำนวณด้วยตัวเองเพราะฉันต้องการมันสำหรับแอพของฉัน คุณยังสามารถใช้ทรัพยากรการหรี่แสงแทนสไตล์
JJ86

ตัวเลขระยะขอบจะแตกต่างกันขึ้นอยู่กับที่elevationคุณตั้งค่าไว้ใน FAB
Jarett Millard

ใช้app:useCompatPadding="true"
Kishan Vaghela

51

ไม่มีการเล่นซอกับstyles.xmlหรือ.javaไฟล์ ขอฉันทำให้มันง่าย

คุณสามารถใช้app:useCompatPadding="true"และลบระยะขอบที่กำหนดเองเพื่อรักษาระยะขอบเดียวกันใน Android เวอร์ชันต่างๆ

ระยะขอบพิเศษ / ช่องว่างภายในที่คุณเห็นบน FAB ในภาพที่สองของคุณเกิดจากการใช้งานร่วมกันได้บนอุปกรณ์อมยิ้มก่อน หากไม่ได้ตั้งค่าคุณสมบัตินี้คุณสมบัตินี้จะถูกนำไปใช้กับอุปกรณ์pre-lollopopและไม่ได้อยู่ในอุปกรณ์ lollipop +

รหัสสตูดิโอ android

หลักฐานแนวคิด

มุมมองการออกแบบ


หากเค้าโครงหลักเป็นมุมมองการ์ดเราจำเป็นต้องใช้ "card_view: useCompatPadding =" true "สำหรับ fab
Amit Tumkur

สิ่งนี้ใช้ได้กับฉันหลังจากอัปเกรดไลบรารีการสนับสนุนเป็นเวอร์ชัน 23.2 ขอบคุณ!
Pablo

ฉันเห็นระยะขอบใน PoC ของคุณ
Pedro Oliveira

@PedroOliveira ใช่คุณจะเห็นระยะขอบเดียวกันในทุกเวอร์ชันของ Android ซึ่งในความเป็นจริงคือวัตถุประสงค์
Saravanabalagi Ramachandran

1
คุณกำลังบอกว่าเขาสามารถใช้ "xxx" เพื่อลบระยะขอบที่กำหนดเองได้ แต่การพิสูจน์แนวคิดของคุณก็ยังแสดงระยะขอบทั้งหมดเช่น OP ถามว่าทำไม
Pedro Oliveira

31

หลังจากค้นหาและทดสอบวิธีแก้ปัญหาไม่กี่ครั้งฉันแก้ไขปัญหาด้วยการเพิ่มบรรทัดนี้ในรูปแบบ xml ของฉันเท่านั้น:

app:elevation="0dp"
app:pressedTranslationZ="0dp"

และนี่คือรูปแบบปุ่มลอยทั้งหมดของฉัน

<android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_marginRight="16dp"
        android:layout_marginBottom="16dp"
        android:src="@drawable/ic_add"
        app:elevation="0dp"
        app:pressedTranslationZ="0dp"
        app:fabSize="normal" />

2
เยี่ยมมากทำงานให้ฉัน ไม่มีuseCompatPaddingสิ่งอื่นใดได้รับผลเช่นเดียวกัน
bgplaya

1
ฉันได้รวมคำตอบนี้เข้ากับvikram's
ingkevin

22

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

อัปเดตตัวอย่างการทำงาน

XML - FAB อยู่ใน RelativeLayout

<android.support.design.widget.FloatingActionButton
    android:id="@+id/fab"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_alignParentRight="true"
    android:layout_marginBottom="16dp"
    android:layout_marginRight="16dp"
    android:src="@mipmap/ic_add"
    app:backgroundTint="@color/accent"
    app:borderWidth="0dp"
    app:elevation="4sp"/>

Java

FloatingActionButton mFab = (FloatingActionButton) v.findViewById(R.id.fab);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
    ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams) mFab.getLayoutParams();
    p.setMargins(0, 0, dpToPx(getActivity(), 8), 0); // get rid of margins since shadow area is now the margin
    mFab.setLayoutParams(p);
}

แปลง dp เป็น px

public static int dpToPx(Context context, float dp) {
    // Reference http://stackoverflow.com/questions/8309354/formula-px-to-dp-dp-to-px-android
    float scale = context.getResources().getDisplayMetrics().density;
    return (int) ((dp * scale) + 0.5f);
}

อมยิ้ม

ใส่คำอธิบายภาพที่นี่

พรีอมยิ้ม

ใส่คำอธิบายภาพที่นี่


นี่น่าจะเป็นคำตอบที่ถูกต้อง อย่างไรก็ตามไม่สามารถแก้ไขปัญหาได้ 100% เนื่องจากช่องว่างภายในไม่ได้กำลังสองเช่นกัน
JohnnyLambada

@JohnnyLambada ฉันไม่คิดอย่างนั้น RelativeLayout.LayoutParamsไม่สามารถส่งไปที่LayoutParamsของFloatingActionButtonและฉันไม่เห็นระยะขอบของ 16dp ใด ๆ ใน pre Lollipop ความกว้างของFloatingActionButtonอมยิ้มก่อนคือ 84dp แทนที่จะเป็น 56dp และความสูงคือ 98dp
Markus Rubey

@MarkusRubey ฉันจะอัปเดตคำตอบของฉันด้วยตัวอย่างการทำงานและรูปภาพที่แสดงเวอร์ชันก่อนอมยิ้มและอมยิ้ม
Eugene H

1
@MarkusRubey - View.getLayoutParamsส่งกลับLayoutParamsประเภทของViewis in - ในกรณีของ Eugene มันคือไฟล์RelativeLayout.LayoutParams.
JohnnyLambada

1
@EugeneH ฉันเปลี่ยน RelativeLayout.LayoutParams เป็น ViewGroup.MarginLayoutParams สิ่งนี้จะทำให้โค้ดใช้งานได้ในหลาย ๆ กรณีและแก้ไขปัญหาที่ MarkusRubey แสดงขึ้นมา
JohnnyLambada

8

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

import android.content.Context;
import android.content.res.TypedArray;
import android.support.design.widget.FloatingActionButton;
import android.util.AttributeSet;
import android.view.ViewGroup.MarginLayoutParams;

import static android.os.Build.VERSION.SDK_INT;
import static android.os.Build.VERSION_CODES.LOLLIPOP;

import static android.support.design.R.styleable.FloatingActionButton;
import static android.support.design.R.styleable.FloatingActionButton_fabSize;
import static android.support.design.R.style.Widget_Design_FloatingActionButton;
import static android.support.design.R.dimen.fab_size_normal;
import static android.support.design.R.dimen.fab_size_mini;

public class CustomFloatingActionButton extends FloatingActionButton {

    private int mSize;

    public CustomFloatingActionButton(Context context) {
        this(context, null);
    }

    public CustomFloatingActionButton(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CustomFloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a = context.obtainStyledAttributes(attrs, FloatingActionButton, defStyleAttr,
                Widget_Design_FloatingActionButton);
        this.mSize = a.getInt(FloatingActionButton_fabSize, 0);
        a.recycle();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (SDK_INT < LOLLIPOP) {
            int size = this.getSizeDimension();
            int offsetVertical = (h - size) / 2;
            int offsetHorizontal = (w - size) / 2;
            MarginLayoutParams params = (MarginLayoutParams) getLayoutParams();
            params.leftMargin = params.leftMargin - offsetHorizontal;
            params.rightMargin = params.rightMargin - offsetHorizontal;
            params.topMargin = params.topMargin - offsetVertical;
            params.bottomMargin = params.bottomMargin - offsetVertical;
            setLayoutParams(params);
        }
    }

    private final int getSizeDimension() {
        switch (this.mSize) {
            case 0: default: return this.getResources().getDimensionPixelSize(fab_size_normal);
            case 1: return this.getResources().getDimensionPixelSize(fab_size_mini);
        }
    }
}

อัปเดต: Android Support Libraries v23 เปลี่ยนชื่อ fab_size ลดขนาดเป็น:

import static android.support.design.R.dimen.design_fab_size_normal;
import static android.support.design.R.dimen.design_fab_size_mini;

ฉันเพิ่งปรับโครงสร้างโปรเจ็กต์ของฉันเป็น AndroidX และฉันไม่สามารถสร้างคอนสตรัคเตอร์ที่ 3 จากตัวอย่างของคุณได้ ฉันจะใช้ไลบรารี AndroidX ได้อย่างไร
Alon Shlider

5

คำตอบของ Markusทำงานได้ดีสำหรับฉันหลังจากอัปเดตเป็น v23.1.0 และทำการปรับเปลี่ยนการนำเข้าบางอย่าง (ด้วยปลั๊กอิน gradle ล่าสุดเราใช้แอป R แทน R ของไลบรารีการออกแบบ) นี่คือรหัสสำหรับ v23.1.0:

// Based on this answer: https://stackoverflow.com/a/30845164/1317564
public class CustomFloatingActionButton extends FloatingActionButton {
    private int mSize;

    public CustomFloatingActionButton(Context context) {
        this(context, null);
    }

    public CustomFloatingActionButton(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    @SuppressLint("PrivateResource")
    public CustomFloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.FloatingActionButton, defStyleAttr,
                R.style.Widget_Design_FloatingActionButton);
        mSize = a.getInt(R.styleable.FloatingActionButton_fabSize, 0);
        a.recycle();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            int size = this.getSizeDimension();
            int offsetVertical = (h - size) / 2;
            int offsetHorizontal = (w - size) / 2;
            ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) getLayoutParams();
            params.leftMargin = params.leftMargin - offsetHorizontal;
            params.rightMargin = params.rightMargin - offsetHorizontal;
            params.topMargin = params.topMargin - offsetVertical;
            params.bottomMargin = params.bottomMargin - offsetVertical;
            setLayoutParams(params);
        }
    }

    @SuppressLint("PrivateResource")
    private int getSizeDimension() {
        switch (mSize) {
            case 1:
                return getResources().getDimensionPixelSize(R.dimen.design_fab_size_mini);
            case 0:
            default:
                return getResources().getDimensionPixelSize(R.dimen.design_fab_size_normal);
        }
    }
}

ดูเหมือนว่าฉันจะใช้ตัวอย่างนี้ไม่ได้หลังจากปรับโครงสร้างเป็น AndroidX - ตัวสร้างที่ 3 ไม่รวบรวมอีกต่อไป รู้อะไรผิดหรือเปล่า
Alon Shlider

3

ในไฟล์เค้าโครงตั้งค่าการยกระดับแอตทริบิวต์เป็น 0 เนื่องจากใช้การยกระดับเริ่มต้น

app:elevation="0dp"

ขณะนี้อยู่ในระดับ api ตรวจสอบกิจกรรมที่มากกว่า 21 และตั้งค่าระดับความสูงหากจำเป็น

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    fabBtn.setElevation(10.0f);
}

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