Android: 如何在警报对话框的按钮前添加一条灰色水平细线?

Android: How do I add a thin grey horizontal line on alert-dialog before the buttons?

我正在使用 android.app.AlertDialog,它包含一个 ScrollView 和内部(当然)一些内容。

Google 在其 material 指南中显示当内容大于可见内容时按钮上方的灰色小线 space: http://www.google.com/design/spec/components/dialogs.html#dialogs-behavior

我的警报对话框没有这条灰线。如何创建这条线?

我已经尝试过这样的 ScrollView 背景:

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
   <stroke
       android:width="1dp"
       android:color="@color/dark_transparent"/>
</shape>

但这在顶部和底部创建了一条线。而且当内容小于可见的时候也会出现space,看起来很难看。

在您的 ScrollView 下方添加如下内容:

<View android:layout_width="fill_parent"
android:layout_height="2px"
android:background="#90909090"/>

它应该给你一个细长的灰色单杠。

我找到了解决灰线的方法! :)

我在这里找到了如何显示灰线的解决方案:How to make a static button under a ScrollView?

为了检查是否要显示它,我在这里找到了解决方案:How can you tell when a layout has been drawn?

这就是我的代码现在的样子:

这是my_material_dialog.xml:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <ScrollView
        android:id="@+id/myMaterialDialog_scrollView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:fillViewport="true">

        <LinearLayout
            android:id="@+id/myMaterialDialog_textView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:paddingBottom="5dp"
            android:paddingLeft="26dp"
            android:paddingRight="26dp"
            android:paddingTop="15dp">
            <!-- dynamically added content goes here -->
        </LinearLayout>
    </ScrollView>

    <View
        android:id="@+id/myMaterialDialog_lineView"
        android:layout_width="fill_parent"
        android:layout_height="1dp"
        android:layout_gravity="center_horizontal"
        android:background="#15000000"
        android:gravity="center_horizontal"
        android:visibility="gone"/>

</LinearLayout>

这是MyMaterialDialog.java:

public class MyMaterialDialog extends AlertDialog {

  private Context context;
  private ScrollView scrollView;
  private LinearLayout textView;
  private View lineView;
  private boolean checkingLayout;

  public MyMaterialDialog(final Context context) {
    super(context);
    this.context = context;

    final View myMaterialDialog = getLayoutInflater().inflate(R.layout.my_material_dialog, null);
    this.scrollView = (ScrollView) myMaterialDialog.findViewById(R.id.myMaterialDialog_scrollView);
    this.textView = (LinearLayout) myMaterialDialog.findViewById(R.id.myMaterialDialog_textView);
    this.lineView = myMaterialDialog.findViewById(R.id.myMaterialDialog_lineView);

    final ViewTreeObserver vto = scrollView.getViewTreeObserver();
    vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
      @Override
      public void onGlobalLayout() {
        if (checkingLayout) {
          // avoid infinite recursions
          return;
        }

        checkingLayout = true;
        if (scrollView.canScrollVertically(1)) {
          lineView.setVisibility(View.VISIBLE);
        } else {
          lineView.setVisibility(View.GONE);
        }
        checkingLayout = false;
      }
    });

    setTitle(R.string.myMaterialDialog_title);
    setText();
    setView(myMaterialDialog);

    show();
  }

  /**
   * do request to webserver for texts
   */
  private final void setText() {
    final GetDialogTextRequest request = new GetDialogTextRequest();
    final GetDialogTextResultHandler resultHandler = new GetDialogTextResultHandler(context, textView);

    request.submit(resultHandler);
  }
}

private final class GetDialogTextResultHandler extends DefaultRequestResultHandler<List<MyTextObject>> {

  private final Context context;
  private final LinearLayout textView;

  private GetDialogTextResultHandler(final Context context, final LinearLayout textView) {
    super(context);
    this.context = context;
    this.textView = textView;
  }

  @Override
  public void handleResult(final List<MyTextObject> texts) {
    setText(texts); // ... sets the content, can vary in size
  }
}

如果您使用的是 API 23+ (Android 6.0),在滚动视图中使用以下内容将添加顶部和底部指示器。

android:scrollIndicators="top|bottom"

如果针对较早的 API,我查看了 Google 的警报对话框控制器源代码,并使用了以下代码:

private static void setScrollIndicators(ViewGroup root, final NestedScrollView content,
                                        final int indicators, final int mask) {

//        use it like this: 
//        setScrollIndicators(contentPanel, content, indicators,
//        ViewCompat.SCROLL_INDICATOR_TOP | ViewCompat.SCROLL_INDICATOR_BOTTOM);

// Set up scroll indicators (if present).
    View indicatorUp = root.findViewById(R.id.scrollIndicatorUp);
    View indicatorDown = root.findViewById(R.id.scrollIndicatorDown);

    if (Build.VERSION.SDK_INT >= 23) {
        // We're on Marshmallow so can rely on the View APIsaa
        ViewCompat.setScrollIndicators(content, indicators, mask);
        // We can also remove the compat indicator views
        if (indicatorUp != null) {
            root.removeView(indicatorUp);
        }
        if (indicatorDown != null) {
            root.removeView(indicatorDown);
        }
    } else {
        // First, remove the indicator views if we're not set to use them
        if (indicatorUp != null && (indicators & ViewCompat.SCROLL_INDICATOR_TOP) == 0) {
            root.removeView(indicatorUp);
            indicatorUp = null;
        }
        if (indicatorDown != null && (indicators & ViewCompat.SCROLL_INDICATOR_BOTTOM) == 0) {
            root.removeView(indicatorDown);
            indicatorDown = null;
        }

        if (indicatorUp != null || indicatorDown != null) {
            final View top = indicatorUp;
            final View bottom = indicatorDown;

            if (content != null) {
                // We're just showing the ScrollView, set up listener.
                content.setOnScrollChangeListener(
                        new NestedScrollView.OnScrollChangeListener() {
                            @Override
                            public void onScrollChange(NestedScrollView v, int scrollX,
                                                       int scrollY,
                                                       int oldScrollX, int oldScrollY) {
                                manageScrollIndicators(v, top, bottom);
                            }
                        });
                // Set up the indicators following layout.
                content.post(new Runnable() {
                    @Override
                    public void run() {
                        manageScrollIndicators(content, top, bottom);
                    }
                });
            } else {
                // We don't have any content to scroll, remove the indicators.
                if (top != null) {
                    root.removeView(top);
                }
                if (bottom != null) {
                    root.removeView(bottom);
                }
            }
        }
    }
}

private static void manageScrollIndicators(View v, View upIndicator, View downIndicator) {
    if (upIndicator != null) {
        upIndicator.setVisibility(
                ViewCompat.canScrollVertically(v, -1) ? View.VISIBLE : View.INVISIBLE);
    }
    if (downIndicator != null) {
        downIndicator.setVisibility(
                ViewCompat.canScrollVertically(v, 1) ? View.VISIBLE : View.INVISIBLE);
    }
}

而 XML 看起来像这样:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<View
    android:id="@+id/scrollIndicatorUp"
    android:layout_width="match_parent"
    android:layout_height="1dp"
    android:background="@color/dim_white"
    android:visibility="gone"
    tools:visibility="visible" />

<android.support.v4.widget.NestedScrollView
    android:id="@+id/scrollView"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1">

    <... you content here>

</android.support.v4.widget.NestedScrollView>

<View
    android:id="@+id/scrollIndicatorDown"
    android:layout_width="match_parent"
    android:layout_height="1dp"
    android:background="@color/dim_white"
    android:visibility="gone"
    tools:visibility="visible" />
</LinearLayout>