0

I'm using android.app.AlertDialog that contains a ScrollView and inside (of course) some content.

Google shows in its material-guidelines a small grey line above the buttons when the content is larger than the visible space: http://www.google.com/design/spec/components/dialogs.html#dialogs-behavior

My alert-dialog doesn't have this grey line. How do I create this line?

I already tried a background for the ScrollView like this:

<?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>

But this created a line on top AND bottom. And it also appears when the content is smaller than the visible space, which looks ugly.

nyx
  • 477
  • 1
  • 4
  • 10

3 Answers3

2

I found a solution for the grey line! :)

I found the solution how to show the grey line at all here: How to make a static button under a ScrollView?

For the check if I want to show it, I found the solution here: How can you tell when a layout has been drawn?

This is how my code looks like now:

This is 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>

And this is 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
  }
}
Community
  • 1
  • 1
nyx
  • 477
  • 1
  • 4
  • 10
1

Add something like this below your ScrollView:

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

It should give you a slim greyish horizontal bar.

Jonas Czech
  • 12,018
  • 6
  • 44
  • 65
  • hm, not really working. When I add the View like you said, then I have to add another LinearLayout around both the ScrollView and the new element, because there's only one root element allowed. Then the line appears ONLY when there's no scrolling. As soon as the content is larger than the visible space the line disappears. But I wanted it the other way round: only a line when there's scrolling. – nyx Feb 10 '15 at 13:17
  • Maybe you could use a relative layout, and then you can position it properly. [See this answer](http://stackoverflow.com/a/8271429/4428462). To make it show only when scrolling is possible you could find out if your scrollView is scrollable in your code (try getting the height of the content and the height of the scrollView, and see if the first is bigger than the second), and show / hide the horizontal bar view as appropriate. – Jonas Czech Feb 10 '15 at 15:31
  • Hm, it's not so easy... When I use a RelativeLayout I have to set the height to wrap_content. The height of the ScrollView is also wrap_content. Now when I set for the ScrollView layout_alignParentTop="true" and for the Line-View android:layout_alignParentBottom="true" it works for the Line. But now I have the problem that the height of the dialog is always at maximum, even if there's only little content. If I use android:layout_below="@id/scrollView" for the Line-View the size of the dialog is right, but now the Line only appears when there's no scrolling. Same behaviour as with LinearLayout. – nyx Feb 11 '15 at 12:53
1

If you're using API 23+ (Android 6.0) using the following in scroll view will add the top and bottom indicators.

android:scrollIndicators="top|bottom"

If targeting older API's I looked into Google's Alert Dialog controller source code, and am using the following code:

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);
    }
}

And XML looks like this:

<?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>
Nishant Singh
  • 645
  • 7
  • 16