[android] Android : 기본 설정 화면에서 여백 / 패딩을 제거하는 방법

환경 설정 화면을 디자인하는 데 매우 이상한 문제가 있습니다. 레이아웃에 여백을주지 않지만 왼쪽에 약간의 공간이 남습니다.

아래 이미지에서 볼 수 있듯이 :
여기에 이미지 설명 입력

XML :

   <PreferenceScreen android:title="demo" >
       <CheckBoxPreference
           android:defaultValue="false"
            android:key="prefSync"`
            android:title="Auto Sync" />
    </PreferenceScreen>

화면에 체크 박스 기본 설정을 추가하는 데 문제가 있습니까?



답변

androidx 용으로 업데이트 중입니다.

많은 실험을 거친 후 과도한 들여 쓰기가있는 각 기본 설정에 다음 추가하여이 문제를 해결했습니다 .

app:iconSpaceReserved="false"

물론 xml 맨 위에있는 PreferenceScreen 선언 자체에도 이것을 추가해야합니다.

xmlns:app="http://schemas.android.com/apk/res-auto"

사용자 지정 기본 설정에 대한 후속 조치

사용자 지정 기본 설정의 경우, 특히 오래된 장치에서이 솔루션이 항상 작동하는 것은 아니라는 것을 알았습니다. 예를 들어 다음과 같은 기본 설정은 여전히 ​​들여 쓰기 될 수 있습니다.

com.example.preference.SomeCustomPreference
    android:id="@+id/some_custom_preference"
    android:name="Custom Preference"
    android:key="@string/custom_pref_key"
    android:summary="@string/custom_pref_summary"
    android:title="@string/preference_custom_title"
    app:iconSpaceReserved="false"

이 문제는 사용자 지정 기본 설정 클래스에서 세 번째 생성자 매개 변수의 사용을 추적합니다. 세 번째 매개 변수를 전달하면 목록 항목이 들여 쓰기됩니다. 생략하면 목록이 올바르게 정렬됩니다.

class SomeCustomPreference
@JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = android.R.attr.someCustomPreferenceStyle
) : DialogPreference(context, attrs, defStyle) {

    override fun getDialogLayoutResource(): Int {
        return R.layout.my_layout
    }
}

그 대신 다음을 사용하십시오.

class SomeCustomPreference
@JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null
) : DialogPreference(context, attrs) {

    override fun getDialogLayoutResource(): Int {
        return R.layout.my_layout
    }
}

이것에 대한 크레딧은이 아주 오래된 포스트의 @CommonsWare로 이동합니다 .


답변

여기 에서이 문제에 대해보고 했지만 (거기에서 내 해결 방법 프로젝트를 확인할 수도 있습니다), 지금은 약간 해킹이되었지만이를 극복 할 수있는 쉬운 방법을 찾았습니다.

  • 의 경우 PreferenceCategory레이아웃의 시작 / 왼쪽 패딩을 0으로 설정했습니다.

  • 다른 유형의 환경 설정의 icon_frame경우 아이콘이없는 경우 숨기기를 선택 합니다.

여기에 코드가 있습니다. 이 클래스에서 확장하면 나머지는 자동입니다.

Kotlin

abstract class BasePreferenceFragment : PreferenceFragmentCompat() {

    override fun onCreateAdapter(preferenceScreen: PreferenceScreen?): RecyclerView.Adapter<*> {
        return object : PreferenceGroupAdapter(preferenceScreen) {
            override fun onBindViewHolder(holder: PreferenceViewHolder, position: Int) {
                super.onBindViewHolder(holder, position)
                val preference = getItem(position)
                if (preference is PreferenceCategory)
                    setZeroPaddingToLayoutChildren(holder.itemView)
                else
                    holder.itemView.findViewById<View?>(R.id.icon_frame)?.visibility = if (preference.icon == null) View.GONE else View.VISIBLE
            }
        }
    }

    private fun setZeroPaddingToLayoutChildren(view: View) {
        if (view !is ViewGroup)
            return
        val childCount = view.childCount
        for (i in 0 until childCount) {
            setZeroPaddingToLayoutChildren(view.getChildAt(i))
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
                view.setPaddingRelative(0, view.paddingTop, view.paddingEnd, view.paddingBottom)
            else
                view.setPadding(0, view.paddingTop, view.paddingRight, view.paddingBottom)
        }
    }
}

자바

public abstract class BasePreferenceFragmentCompat extends PreferenceFragmentCompat {
    @Override
    protected RecyclerView.Adapter onCreateAdapter(PreferenceScreen preferenceScreen) {
        return new PreferenceGroupAdapter(preferenceScreen) {
            @SuppressLint("RestrictedApi")
            @Override
            public void onBindViewHolder(PreferenceViewHolder holder, int position) {
                super.onBindViewHolder(holder, position);
                Preference preference = getItem(position);
                if (preference instanceof PreferenceCategory)
                    setZeroPaddingToLayoutChildren(holder.itemView);
                else {
                    View iconFrame = holder.itemView.findViewById(R.id.icon_frame);
                    if (iconFrame != null) {
                        iconFrame.setVisibility(preference.getIcon() == null ? View.GONE : View.VISIBLE);
                    }
                }
            }
        };
    }

    private void setZeroPaddingToLayoutChildren(View view) {
        if (!(view instanceof ViewGroup))
            return;
        ViewGroup viewGroup = (ViewGroup) view;
        int childCount = viewGroup.getChildCount();
        for (int i = 0; i < childCount; i++) {
            setZeroPaddingToLayoutChildren(viewGroup.getChildAt(i));
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
                viewGroup.setPaddingRelative(0, viewGroup.getPaddingTop(), viewGroup.getPaddingEnd(), viewGroup.getPaddingBottom());
            else
                viewGroup.setPadding(0, viewGroup.getPaddingTop(), viewGroup.getPaddingRight(), viewGroup.getPaddingBottom());
        }
    }
}

그리고 결과 ( 이 Google 샘플 의 XML 샘플은 여기 에서 찾을 수 있습니다. 여기 에서 확인하기 위해 생성 했습니다.)

여기에 이미지 설명 입력

이 코드는 약간 위험하므로 라이브러리를 업데이트 할 때마다 제대로 작동하는지 확인하십시오.

또한 android:layout기본 설정을 직접 정의 할 때와 같은 일부 특수한 경우에는 제대로 작동하지 않을 수 있으므로이 문제에 대해 수정해야합니다.


더 나은 공식 솔루션이 있습니다.

각 환경 설정에 대해 app:iconSpaceReserved="false". 이것은 잘 작동하지만 어떤 이유로 PreferenceCategory에서 작동하지 않는 (알려진) 버그가 있습니다. 그것은보고 여기에 , 그리고 가까운 장래에 고정되어야한다.

따라서 지금은 내가 작성한 해결 방법과이 플래그의 혼합 버전을 사용할 수 있습니다.


편집 : 또 다른 해결책을 찾았습니다. 이것은 모든 기본 설정 isIconSpaceReserved을 무시하고 각각에 대해 설정 합니다. 안타깝게도 위에서 썼 듯이 PreferenceCategory를 사용하면 파괴되지만 사용하지 않으면 정상적으로 작동합니다.

Kotlin

abstract class BasePreferenceFragment : PreferenceFragmentCompat() {

    override fun setPreferenceScreen(preferenceScreen: PreferenceScreen?) {
        super.setPreferenceScreen(preferenceScreen)
        if (preferenceScreen != null) {
            val count = preferenceScreen.preferenceCount
            for (i in 0 until count)
                preferenceScreen.getPreference(i)!!.isIconSpaceReserved = false
        }
    }

자바

public class BasePreferenceFragment extends PreferenceFragmentCompat {

    @Override
    public void setPreferenceScreen(PreferenceScreen preferenceScreen) {
        super.setPreferenceScreen(preferenceScreen);
        if (preferenceScreen != null) {
            int count = preferenceScreen.getPreferenceCount();
            for (int i = 0; i < count; i++)
                preferenceScreen.getPreference(i).setIconSpaceReserved(false);
        }
    }
}

편집 : Google이 마침내 라이브러리를 수정 한 후 ( 여기 링크 ) 각 환경 설정에 대한 플래그를 설정하거나 모두를 위해이 솔루션을 사용할 수 있습니다.

abstract class BasePreferenceFragment : PreferenceFragmentCompat() {
    private fun setAllPreferencesToAvoidHavingExtraSpace(preference: Preference) {
        preference.isIconSpaceReserved = false
        if (preference is PreferenceGroup)
            for (i in 0 until preference.preferenceCount)
                setAllPreferencesToAvoidHavingExtraSpace(preference.getPreference(i))
    }

    override fun setPreferenceScreen(preferenceScreen: PreferenceScreen?) {
        if (preferenceScreen != null)
            setAllPreferencesToAvoidHavingExtraSpace(preferenceScreen)
        super.setPreferenceScreen(preferenceScreen)

    }

    override fun onCreateAdapter(preferenceScreen: PreferenceScreen?): RecyclerView.Adapter<*> =
            object : PreferenceGroupAdapter(preferenceScreen) {
                @SuppressLint("RestrictedApi")
                override fun onPreferenceHierarchyChange(preference: Preference?) {
                    if (preference != null)
                        setAllPreferencesToAvoidHavingExtraSpace(preference)
                    super.onPreferenceHierarchyChange(preference)
                }
            }
}

그것에서 확장하면 선호도에 쓸모없는 패딩이 없습니다. 여기에 샘플 프로젝트가 있습니다 . 여기서는 그러한 트릭 대신 공식적인 방법을 요청합니다. 주연을 고려하십시오.


답변

여기 에서 간단한 작업 솔루션 .
모든 기본 설정에 쓸 필요없이 모든 기본 설정에서 작동합니다.app:iconSpaceReserved="false"

만들기 res/values-sw360dp/values-preference.xml:

<resources xmlns:tools="http://schemas.android.com/tools">
    <bool name="config_materialPreferenceIconSpaceReserved" tools:ignore="MissingDefaultResource,PrivateResource">false</bool>
    <dimen name="preference_category_padding_start" tools:ignore="MissingDefaultResource,PrivateResource">0dp</dimen>
</resources>

<bool>수정의 기본 값 iconSpacePreserved모든 Preference; 는 <dimen>PreferenceCategory를 해결.

편집 : 사용하는 경우 androidx.preference:preference:1.1.1치수가 필요하지 않습니다 preference_category_padding_start. Android 6-10에서 테스트되었습니다.


답변

이 시도:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View v = super.onCreateView(inflater, container, savedInstanceState);
    if(v != null) {
        ListView lv = (ListView) v.findViewById(android.R.id.list);
        lv.setPadding(10, 10, 10, 10);
    }
    return v;
}

다음을 사용하여 패딩을 설정할 수 있습니다. setPadding();


답변

com.android.support:preference-v7라이브러리를 사용하는 경우 환경 설정을 호스팅하는 활동의 테마 preferenceTheme가 v14 Material 환경 설정 테마 오버레이 로 설정되어 있는지 확인하십시오 .

<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>


답변

불행히도 위의 아무것도 나를 위해 일하지 않았습니다.

짧은 대답 :

사용자 지정 기본 설정 레이아웃의 맨 위 컨테이너에 음수 여백 을 사용하여이 문제를 해결했습니다 .

단계 :

  • 기본 설정에 대한 사용자 지정 레이아웃 만들기 (예 : preferences_category.xml)
  • XML의 환경 설정 태그에 android : layout param을 추가하여 환경 설정이 사용자 정의 레이아웃을 사용하도록 지정
  • 마이너스 여백 적용

자세한 답변 :

기본 설정 XML :

    <android.support.v7.preference.PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:title="@string/settings_title" >

    <android.support.v7.preference.PreferenceCategory
        android:layout="@layout/preference_category"
        android:key="settings_list"
        android:title="@string/pref_category_settings" />
    <android.support.v7.preference.SwitchPreferenceCompat
        android:layout="@layout/preference_row"
        android:icon="@drawable/ic_nav_switch"
        android:key="pref_switch"
        android:title="@string/pref_switch_title" />

    </android.support.v7.preference.PreferenceScreen>

불필요한 왼쪽 및 오른쪽 여백을 제거하는 기본 설정 행의 사용자 지정 레이아웃 :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginStart="-12dp"
    android:layout_marginEnd="-8dp"
    android:minHeight="?android:attr/listPreferredItemHeight"
    android:gravity="center_vertical">

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">

        <ImageView
            android:id="@android:id/icon"
            android:layout_width="58dp"
            android:layout_height="58dp"
            android:padding="8dp"
            android:layout_gravity="center"
            android:visibility="visible" />

    </RelativeLayout>

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="15dp"
        android:layout_marginEnd="6dp"
        android:layout_marginTop="6dp"
        android:layout_marginBottom="6dp"
        android:layout_weight="1">

        <TextView
            android:id="@android:id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:singleLine="true"
            android:textAppearance="?android:attr/textAppearanceListItem"
            android:ellipsize="marquee"
            android:fadingEdge="horizontal" />

        <TextView
            android:id="@android:id/summary"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@android:id/title"
            android:layout_alignStart="@android:id/title"
            android:textAppearance="?android:attr/textAppearanceListItemSecondary"
            android:textColor="?android:attr/textColorSecondary"
            android:maxLines="2"/>

    </RelativeLayout>

    <LinearLayout
        android:id="@android:id/widget_frame"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:gravity="end|center_vertical"
        android:orientation="vertical">

    </LinearLayout>
</LinearLayout>

불필요한 왼쪽 및 오른쪽 여백을 제거하는 기본 설정 범주에 대한 사용자 지정 레이아웃 :

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textColor="@color/colorAccent"
    android:textStyle="bold"
    android:textSize="12sp"
    android:gravity="center_vertical"
    android:textAllCaps="true"
    android:layout_marginStart="-4dp"
    android:layout_marginEnd="-8dp"
    android:id="@+android:id/title" />


답변

패딩은 설정을 포함 하는 부모 ListView에 의해 발생 PreferenceScreen합니다. PreferenceFragment를 사용하여 환경 설정을 만드는 경우 의 onActivityCreated기능으로 이동 PreferenceFragement하여 다음을 수행하여 패딩을 제거하십시오.

public void onActivityCreated(Bundle savedInstanceState) {
  super.onActivityCreated(savedInstanceState);

  View lv = getView().findViewById(android.R.id.list);
  if (lv != null) lv.setPadding(0, 0, 0, 0);
}