사용자 정의보기가있는 AlertDialog :보기의 내용을 래핑하도록 크기 조정
내가 만드는 응용 프로그램에서이 문제가 발생했습니다. 모든 설계 단점과 모범 사례 접근 방식의 부족을 무시하십시오. 이것은 순전히 해결할 수없는 예를 보여주기위한 것입니다.
을 사용하여 사용자 정의 세트 DialogFragment
로 기본을 반환합니다 . 이 경우 특정 크기 요구 사항을 가지고, 내가 어떻게 얻을 않는 올바르게 정의의 모든 콘텐츠를 표시 할 자체의 크기를 조정 ?AlertDialog
View
AlertDialog.Builder.setView()
View
Dialog
View
이것은 내가 사용한 예제 코드입니다.
package com.test.test;
import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Use a button for launching
Button b = new Button(this);
b.setText("Launch");
b.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// Launch the dialog
myDialog d = new myDialog();
d.show(getFragmentManager(), null);
}
});
setContentView(b);
}
public static class myDialog extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Create the dialog
AlertDialog.Builder db = new AlertDialog.Builder(getActivity());
db.setTitle("Test Alert Dialog:");
db.setView(new myView(getActivity()));
return db.create();
}
protected class myView extends View {
Paint p = null;
public myView(Context ct) {
super(ct);
// Setup paint for the drawing
p = new Paint();
p.setColor(Color.MAGENTA);
p.setStyle(Style.STROKE);
p.setStrokeWidth(10);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(800, 300);
}
@Override
protected void onDraw(Canvas canvas) {
// Draw a rectangle showing the bounds of the view
canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), p);
}
}
}
}
A Button
가 생성되고 DialogFragment
클릭 하면 열립니다 . 사용자 정의 View
( myView
)는의 재정의에 올바르게 설정된 너비 800과 높이 300을 가져야합니다 onMeasure()
. 이것은 View
디버깅 목적으로 측정 된 경계를 자홍색으로 그립니다.
800 너비는 Dialog
내 장치 의 기본 크기 보다 넓지 만 올바르게 늘어나지 않고 잘립니다.
다음 솔루션을 살펴 보았습니다.
- DialogFragment.getDialog가 null을 반환합니다.
- Android에서 기본 경고 대화 상자의 너비와 높이를 제어하는 방법은 무엇입니까?
- 경고 대화 상자 또는 사용자 지정 경고 대화 상자의 크기
다음 두 가지 코딩 접근 방식을 추론했습니다.
- 가져 오기
WindowManager.LayoutParams
의를Dialog
하고 사용하여 오버라이드 (override)myDialog.getDialog().getWindow().get/setAttributes()
setLayout(w, h)
방법 사용myDialog.getDialog().getWindow().setLayout()
나는 내가 생각할 수있는 모든 곳에서 시도해 보았고 (재정의 onStart()
, a onShowListener
, Dialog
생성 및 표시 후 등) 일반적으로 특정 값LayoutParams
이 제공 되면 두 가지 방법이 올바르게 작동하도록 할 수 있습니다 . 그러나 공급 될 때마다 아무 일도 일어나지 않습니다.WRAP_CONTENT
어떤 제안?
편집하다:
상황 스크린 샷 :
이유는 이유 -. 다른 필요한 경우 - 특정 값의 스크린 샷 (주 900 850 조정되고있는 전체 창 주어진 의미가보기의 전체 폭을 커버하지 않는, 여기에 제공 그래서를 입력 WRAP_CONTENT
/ 필수 고정 값이 적절하지 않음) :
솔직히 말해서 그런 간단한 결과를 얻기에는 너무 깊이 파고 드는 작업 솔루션이 있습니다. 하지만 여기 있습니다 :
정확히 무슨 일이 일어나고 있는지 :
Hierarchy Viewer로Dialog
레이아웃 을 열면의 전체 레이아웃 과 정확히 무슨 일이 벌어지고 있는지 조사 할 수있었습니다 .AlertDialog
블루 하이라이트 (하이 레벨의 모든 부분이다 Window
위한 프레임 Dialog
시각적 스타일, 등)과의 단부로부터 청색 다운 여기서위한 요소 AlertDialog
이다 ( 적색 = 제목, 황색 어쩌면리스트 용 = A있는 ScrollView 스터브 AlertDialog
의 , 녹색 = Dialog
콘텐츠, 즉 사용자 정의보기, 주황색 = 버튼).
여기에서 7- 뷰 경로 ( 파란색 의 시작 에서 녹색 의 끝까지 )가 올바르게 실패한 것이 분명했습니다 WRAP_CONTENT
. LayoutParams.width
각각을 살펴보면 View
모든 것이 주어 LayoutParams.width = MATCH_PARENT
지고 어딘가에 크기가 설정되어 있음을 알 수 있습니다. 당신이 그 나무를 따르는 경우에 따라서는 사용자 정의 분명하다 View
트리의 하단에이 것 결코 의 크기에 영향을 미칠 수 없습니다 Dialog
.
그렇다면 기존 솔루션은 무엇을하고 있었습니까?
- 의 두 가지 코딩 방법 내 질문에 언급 단순히 상단을지고 있었다
View
및 수정LayoutParams
. 분명히,View
트리의 모든 개체가 부모와 일치하는 경우 최상위 수준이 정적 크기로 설정되면 전체Dialog
크기가 변경됩니다. 그러나 최상위 수준이로 설정되어 있으면 트리WRAP_CONTENT
의 모든 나머지View
개체 는 트리 를 "WRAP their CONTENT" 로 보는 것과는 반대로 여전히 트리 에서 "MATCH their PARENT"를 찾습니다 .
문제 해결 방법 :
무뚝뚝하게 영향을 미치는 경로 LayoutParams.width
의 모든 View
개체를 WRAP_CONTENT
.
의 onStart
라이프 사이클 단계 DialogFragment
가 호출 된 후에 만이 작업을 수행 할 수 있음을 발견했습니다 . 따라서 다음 onStart
과 같이 구현됩니다.
@Override
public void onStart() {
// This MUST be called first! Otherwise the view tweaking will not be present in the displayed Dialog (most likely overriden)
super.onStart();
forceWrapContent(myCustomView);
}
그런 다음 View
계층 구조 를 적절하게 수정하는 기능 LayoutParams
:
protected void forceWrapContent(View v) {
// Start with the provided view
View current = v;
// Travel up the tree until fail, modifying the LayoutParams
do {
// Get the parent
ViewParent parent = current.getParent();
// Check if the parent exists
if (parent != null) {
// Get the view
try {
current = (View) parent;
} catch (ClassCastException e) {
// This will happen when at the top view, it cannot be cast to a View
break;
}
// Modify the layout
current.getLayoutParams().width = LayoutParams.WRAP_CONTENT;
}
} while (current.getParent() != null);
// Request a layout to be re-done
current.requestLayout();
}
그리고 다음은 작업 결과입니다.
왜 전체 Dialog
가 기본 크기에 맞는 모든 케이스를 처리하기 위해 WRAP_CONTENT
명시적인 minWidth
세트를 원하지 않는지 혼란 스럽지만 그럴만 한 이유가 있다고 확신합니다 (듣고 싶을 것입니다) .
후
dialog.show();
그냥 사용
dialog.getWindow().setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, yourHeight);
매우 간단한 솔루션이지만 저에게 효과적입니다. 그래도 대화 상자를 확장하고 있지만 이것이 DialogFragment에서도 작동한다고 가정합니다.
AlertDialog는이 두 개의 창 속성을 사용하여 가능한 가장 작은 크기를 정의하여 태블릿에서 화면 중앙에 적절한 너비로 떠 있습니다.
http://developer.android.com/reference/android/R.attr.html#windowMinWidthMajor http://developer.android.com/reference/android/R.attr.html#windowMinWidthMinor
선택한 기본 대화 상자 스타일을 확장하고 값을 변경하여 고유 한 논리를 적용 할 수 있습니다.
이것은 나를 위해 잘 작동했습니다.
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.copyFrom(dialog.getWindow().getAttributes());
lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
dialog.show();
dialog.getWindow().setAttributes(lp);
BT의 답변 에서 한 가지 문제를 발견했습니다 . 대화 상자가 할당 된 상태로 남았습니다 (화면 중앙이 아님). 이 문제를 해결하기 위해 부모 레이아웃의 중력 변경을 추가했습니다. 업데이트 된 forceWrapContent () 메서드를 참조하세요.
protected void forceWrapContent(View v) {
// Start with the provided view
View current = v;
// Travel up the tree until fail, modifying the LayoutParams
do {
// Get the parent
ViewParent parent = current.getParent();
// Check if the parent exists
if (parent != null) {
// Get the view
try {
current = (View) parent;
ViewGroup.LayoutParams layoutParams = current.getLayoutParams();
if (layoutParams instanceof FrameLayout.LayoutParams) {
((FrameLayout.LayoutParams) layoutParams).
gravity = Gravity.CENTER_HORIZONTAL;
} else if (layoutParams instanceof WindowManager.LayoutParams) {
((WindowManager.LayoutParams) layoutParams).
gravity = Gravity.CENTER_HORIZONTAL;
}
} catch (ClassCastException e) {
// This will happen when at the top view, it cannot be cast to a View
break;
}
// Modify the layout
current.getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT;
}
} while (current.getParent() != null);
// Request a layout to be re-done
current.requestLayout();
}
대화 상자는 내용을 감싸 야합니다.
투명한 배경 과 무게 중심이 있는 match_parent 를 사용하여 부모 레이아웃 을 만들 수 있습니다 . 기본 레이아웃을 그 아래에 놓습니다. 그래서 것 보면 같은 중심 위치 대화 상자를 표시합니다.
이 방법을 사용하면 Scrollview, RecyclerView 및 대화 상자에서 모든 유형의 레이아웃을 사용할 수 있습니다.
public void showCustomDialog(Context context) {
Dialog dialog = new Dialog(context);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.dialog_layout, null, false);
findByIds(view); /*find your views by ids*/
((Activity) context).getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
dialog.setContentView(view);
final Window window = dialog.getWindow();
window.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT);
window.setBackgroundDrawableResource(R.color.colorTransparent);
window.setGravity(Gravity.CENTER);
dialog.show();
}
사용하다 setStyle(STYLE_NORMAL, android.R.style.Theme_Holo_Light_Dialog);
AppCompatDialog를 사용하십시오.
import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.AppCompatDialog;
import android.view.Window;
import android.widget.ProgressBar;
public class ProgressDialogCompat extends AppCompatDialog {
public ProgressDialogCompat(Context context) {
super(context);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
Context context = getContext();
int padding = context.getResources().getDimensionPixelSize(R.dimen.x_medium);
ProgressBar progressBar = new ProgressBar(context);
progressBar.setPadding(padding, padding, padding, padding);
setContentView(progressBar);
setCancelable(false);
super.onCreate(savedInstanceState);
}
}
'Development Tip' 카테고리의 다른 글
C # 관리자 권한으로 실행되는지 확인 (0) | 2020.12.29 |
---|---|
JS 힌트-루프 내에서 함수를 만들지 마십시오. (0) | 2020.12.29 |
Python에서 Jinja2의 목록을 JavaScript로 전달하는 방법 (0) | 2020.12.29 |
길이를 알 수없는 입력 문자열을 어떻게 읽을 수 있습니까? (0) | 2020.12.29 |
overflow : hidden + display : inline-block이 텍스트를 위로 이동 (0) | 2020.12.29 |