【问题标题】:Android: How do I add a thin grey horizontal line on alert-dialog before the buttons?Android:如何在按钮前的警报对话框上添加一条细的灰色水平线?
【发布时间】:2015-04-10 10:21:39
【问题描述】:

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

当内容大于可见空间时,Google 在其材料指南中会在按钮上方显示一条灰色小线: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>

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

【问题讨论】:

    标签: android android-layout border android-alertdialog material-design


    【解决方案1】:

    如果您使用 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>
    

    【讨论】:

      【解决方案2】:

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

      我在这里找到了如何显示灰线的解决方案: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
        }
      }
      

      【讨论】:

        【解决方案3】:

        在 ScrollView 下方添加类似的内容:

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

        它应该给你一个细长的灰色水平条。

        【讨论】:

        • 嗯,没用。当我像你说的那样添加 View 时,我必须在 ScrollView 和新元素周围添加另一个 LinearLayout,因为只允许一个根元素。然后该行仅在没有滚动时出现。一旦内容大于可见空间,线条就会消失。但我希望它反过来:滚动时只有一行。
        • 也许您可以使用相对布局,然后您可以正确定位它。 See this answer。要使其仅在可以滚动时显示,您可以在代码中确定您的 scrollView 是否可滚动(尝试获取内容的高度和 scrollView 的高度,并查看第一个是否大于第二个),并显示/ 适当隐藏水平条视图。
        • 嗯,这并不容易......当我使用RelativeLayout时,我必须将高度设置为wrap_content。 ScrollView 的高度也是 wrap_content。现在,当我为 ScrollView layout_alignParentTop="true" 和 Line-View android:layout_alignParentBottom="true" 设置时,它适用于 Line。但是现在我的问题是对话框的高度总是最大,即使只有很少的内容。如果我使用 android:layout_below="@id/scrollView" 作为 Line-View 对话框的大小是正确的,但现在 Line 仅在没有滚动时出现。与 LinearLayout 的行为相同。
        猜你喜欢
        • 1970-01-01
        • 2011-06-07
        • 1970-01-01
        • 2020-06-21
        • 1970-01-01
        • 2020-07-06
        • 1970-01-01
        • 1970-01-01
        • 2014-12-29
        相关资源
        最近更新 更多