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>
我正在使用 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>