mirror of
https://github.com/Tencent/QMUI_Android.git
synced 2026-10-17 04:31:16 +08:00
Dialog bugfix
This commit is contained in:
@@ -74,4 +74,27 @@ public class QMUIWindowHelper {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@SuppressWarnings({"JavaReflectionMemberAccess"})
|
||||
public static Rect unSafeGetContentInsets(View view) {
|
||||
try {
|
||||
// Android P forbid the reflection for @hide filed,
|
||||
// fortunately now it is in light greylist, just be warned.
|
||||
Field field = View.class.getDeclaredField("mAttachInfo");
|
||||
field.setAccessible(true);
|
||||
Object attachInfo = field.get(view);
|
||||
Field visibleInsetsField = attachInfo.getClass().getDeclaredField("mContentInsets");
|
||||
visibleInsetsField.setAccessible(true);
|
||||
Object visibleInsets = visibleInsetsField.get(attachInfo);
|
||||
if (visibleInsets instanceof Rect) {
|
||||
return (Rect) visibleInsets;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.qmuiteam.qmui.R;
|
||||
@@ -52,6 +53,7 @@ import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
|
||||
import androidx.annotation.LayoutRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.AppCompatEditText;
|
||||
import androidx.appcompat.widget.AppCompatImageView;
|
||||
@@ -143,7 +145,7 @@ public class QMUIDialog extends QMUIBaseDialog {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected View onCreateContent(QMUIDialog dialog, QMUIDialogView parent, Context context) {
|
||||
protected View onCreateContent(@NonNull QMUIDialog dialog, @NonNull QMUIDialogView parent, @NonNull Context context) {
|
||||
if (mMessage != null && mMessage.length() != 0) {
|
||||
QMUISpanTouchFixTextView tv = new QMUISpanTouchFixTextView(context);
|
||||
assignMessageTvWithAttr(tv, hasTitle(), R.attr.qmui_dialog_message_content_style);
|
||||
@@ -156,7 +158,7 @@ public class QMUIDialog extends QMUIBaseDialog {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected View onCreateTitle(QMUIDialog dialog, QMUIDialogView parent, Context context) {
|
||||
protected View onCreateTitle(@NonNull QMUIDialog dialog, @NonNull QMUIDialogView parent, @NonNull Context context) {
|
||||
View tv = super.onCreateTitle(dialog, parent, context);
|
||||
if (tv != null && (mMessage == null || mMessage.length() == 0)) {
|
||||
TypedArray a = context.obtainStyledAttributes(null,
|
||||
@@ -843,6 +845,8 @@ public class QMUIDialog extends QMUIBaseDialog {
|
||||
*/
|
||||
public static abstract class AutoResizeDialogBuilder extends QMUIDialogBuilder {
|
||||
|
||||
protected ScrollView mScrollView;
|
||||
|
||||
public AutoResizeDialogBuilder(Context context) {
|
||||
super(context);
|
||||
setCheckKeyboardOverlay(true);
|
||||
@@ -851,7 +855,8 @@ public class QMUIDialog extends QMUIBaseDialog {
|
||||
@Nullable
|
||||
@Override
|
||||
protected View onCreateContent(QMUIDialog dialog, QMUIDialogView parent, Context context) {
|
||||
return wrapWithScroll(onBuildContent(dialog));
|
||||
mScrollView = wrapWithScroll(onBuildContent(dialog));
|
||||
return mScrollView;
|
||||
}
|
||||
|
||||
public abstract View onBuildContent(QMUIDialog dialog);
|
||||
|
||||
@@ -103,12 +103,7 @@ public class QMUIDialogBlockBuilder extends QMUIDialogBuilder<QMUIDialogBlockBui
|
||||
a.recycle();
|
||||
}
|
||||
contentTv.setText(mContent);
|
||||
|
||||
|
||||
QMUIWrapContentScrollView scrollView = new QMUIWrapContentScrollView(context);
|
||||
scrollView.setMaxHeight(getContentAreaMaxHeight());
|
||||
scrollView.addView(contentTv);
|
||||
return scrollView;
|
||||
return wrapWithScroll(contentTv);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.qmuiteam.qmui.R;
|
||||
import com.qmuiteam.qmui.layout.QMUIButton;
|
||||
import com.qmuiteam.qmui.layout.QMUILinearLayout;
|
||||
import com.qmuiteam.qmui.skin.QMUISkinHelper;
|
||||
import com.qmuiteam.qmui.skin.QMUISkinManager;
|
||||
import com.qmuiteam.qmui.skin.QMUISkinValueBuilder;
|
||||
import com.qmuiteam.qmui.util.QMUIDisplayHelper;
|
||||
import com.qmuiteam.qmui.util.QMUIResHelper;
|
||||
@@ -92,9 +93,6 @@ public abstract class QMUIDialogBuilder<T extends QMUIDialogBuilder> {
|
||||
protected List<QMUIDialogAction> mActions = new ArrayList<>();
|
||||
private QMUIDialogView.OnDecorationListener mOnDecorationListener;
|
||||
|
||||
|
||||
private int mContentAreaMaxHeight = -1;
|
||||
|
||||
@Orientation private int mActionContainerOrientation = HORIZONTAL;
|
||||
private boolean mChangeAlphaForPressOrDisable = true;
|
||||
private int mActionDividerThickness = 0;
|
||||
@@ -102,35 +100,18 @@ public abstract class QMUIDialogBuilder<T extends QMUIDialogBuilder> {
|
||||
private int mActionDividerInsetStart = 0;
|
||||
private int mActionDividerInsetEnd = 0;
|
||||
private boolean mCheckKeyboardOverlay = false;
|
||||
private boolean mFollowSkin = true;
|
||||
private QMUISkinManager mSkinManager;
|
||||
private float mMaxPercent = 0.75f;
|
||||
|
||||
public QMUIDialogBuilder(Context context) {
|
||||
this.mContext = context;
|
||||
}
|
||||
|
||||
protected int getContentAreaMaxHeight() {
|
||||
if (mContentAreaMaxHeight == -1) {
|
||||
// 屏幕高度的0.85 - 预估的 title 和 action 高度
|
||||
return (int) (QMUIDisplayHelper.getScreenHeight(mContext) * 0.85) - QMUIDisplayHelper.dp2px(mContext, 100);
|
||||
}
|
||||
return mContentAreaMaxHeight;
|
||||
mSkinManager = QMUISkinManager.defaultInstance(context);
|
||||
}
|
||||
|
||||
public Context getBaseContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置内容区域最高的高度
|
||||
*
|
||||
* @param contentAreaMaxHeight
|
||||
*/
|
||||
public T setContentAreaMaxHeight(int contentAreaMaxHeight) {
|
||||
mContentAreaMaxHeight = contentAreaMaxHeight;
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置对话框顶部的标题文字
|
||||
*/
|
||||
@@ -195,8 +176,8 @@ public abstract class QMUIDialogBuilder<T extends QMUIDialogBuilder> {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public T setFollowSkin(boolean followSkin) {
|
||||
mFollowSkin = followSkin;
|
||||
public T setSkinManager(@Nullable QMUISkinManager skinManager) {
|
||||
mSkinManager = skinManager;
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
@@ -344,6 +325,12 @@ public abstract class QMUIDialogBuilder<T extends QMUIDialogBuilder> {
|
||||
mDialogView = onCreateDialogView(dialogContext);
|
||||
mRootView = new QMUIDialogRootLayout(dialogContext, mDialogView, onCreateDialogLayoutParams());
|
||||
mRootView.setCheckKeyboardOverlay(mCheckKeyboardOverlay);
|
||||
mRootView.setOverlayOccurInMeasureCallback(new QMUIDialogRootLayout.OverlayOccurInMeasureCallback() {
|
||||
@Override
|
||||
public void call() {
|
||||
onOverlayOccurredInMeasure();
|
||||
}
|
||||
});
|
||||
mRootView.setMaxPercent(mMaxPercent);
|
||||
configRootLayout(mRootView);
|
||||
mDialogView = mRootView.getDialogView();
|
||||
@@ -401,12 +388,16 @@ public abstract class QMUIDialogBuilder<T extends QMUIDialogBuilder> {
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
mDialog.setCancelable(mCancelable);
|
||||
mDialog.setCanceledOnTouchOutside(mCanceledOnTouchOutside);
|
||||
mDialog.setFollowSkin(mFollowSkin);
|
||||
mDialog.setSkinManager(mSkinManager);
|
||||
onAfterCreate(mDialog, mRootView, dialogContext);
|
||||
return mDialog;
|
||||
}
|
||||
|
||||
protected void onAfterCreate(QMUIDialog dialog, QMUIDialogRootLayout rootLayout, Context context){
|
||||
protected void onAfterCreate(@NonNull QMUIDialog dialog, @NonNull QMUIDialogRootLayout rootLayout, @NonNull Context context){
|
||||
|
||||
}
|
||||
|
||||
protected void onOverlayOccurredInMeasure(){
|
||||
|
||||
}
|
||||
|
||||
@@ -416,12 +407,12 @@ public abstract class QMUIDialogBuilder<T extends QMUIDialogBuilder> {
|
||||
}
|
||||
}
|
||||
|
||||
protected void configRootLayout(QMUIDialogRootLayout rootLayout){
|
||||
protected void configRootLayout(@NonNull QMUIDialogRootLayout rootLayout){
|
||||
|
||||
}
|
||||
|
||||
@NonNull
|
||||
protected QMUIDialogView onCreateDialogView(Context context){
|
||||
protected QMUIDialogView onCreateDialogView(@NonNull Context context){
|
||||
QMUIDialogView dialogView = new QMUIDialogView(context);
|
||||
dialogView.setBackground(QMUIResHelper.getAttrDrawable(context, R.attr.qmui_skin_support_dialog_bg));
|
||||
dialogView.setRadius(QMUIResHelper.getAttrDimen(context, R.attr.qmui_dialog_radius));
|
||||
@@ -439,7 +430,7 @@ public abstract class QMUIDialogBuilder<T extends QMUIDialogBuilder> {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected View onCreateTitle(QMUIDialog dialog, QMUIDialogView parent, Context context) {
|
||||
protected View onCreateTitle(@NonNull QMUIDialog dialog, @NonNull QMUIDialogView parent, @NonNull Context context) {
|
||||
if (hasTitle()) {
|
||||
TextView tv = new QMUISpanTouchFixTextView(context);
|
||||
tv.setId(R.id.qmui_dialog_title_id);
|
||||
@@ -456,7 +447,7 @@ public abstract class QMUIDialogBuilder<T extends QMUIDialogBuilder> {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
protected ConstraintLayout.LayoutParams onCreateTitleLayoutParams(Context context) {
|
||||
protected ConstraintLayout.LayoutParams onCreateTitleLayoutParams(@NonNull Context context) {
|
||||
ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
lp.leftToLeft = ConstraintLayout.LayoutParams.PARENT_ID;
|
||||
lp.rightToRight = ConstraintLayout.LayoutParams.PARENT_ID;
|
||||
@@ -467,7 +458,7 @@ public abstract class QMUIDialogBuilder<T extends QMUIDialogBuilder> {
|
||||
|
||||
|
||||
@Nullable
|
||||
protected abstract View onCreateContent(QMUIDialog dialog, QMUIDialogView parent, Context context);
|
||||
protected abstract View onCreateContent(@NonNull QMUIDialog dialog, @NonNull QMUIDialogView parent, @NonNull Context context);
|
||||
|
||||
|
||||
protected QMUIWrapContentScrollView wrapWithScroll(@NonNull View view){
|
||||
@@ -477,7 +468,7 @@ public abstract class QMUIDialogBuilder<T extends QMUIDialogBuilder> {
|
||||
return scrollView;
|
||||
}
|
||||
|
||||
protected ConstraintLayout.LayoutParams onCreateContentLayoutParams(Context context) {
|
||||
protected ConstraintLayout.LayoutParams onCreateContentLayoutParams(@NonNull Context context) {
|
||||
ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
lp.leftToLeft = ConstraintLayout.LayoutParams.PARENT_ID;
|
||||
lp.rightToRight = ConstraintLayout.LayoutParams.PARENT_ID;
|
||||
@@ -487,7 +478,7 @@ public abstract class QMUIDialogBuilder<T extends QMUIDialogBuilder> {
|
||||
|
||||
|
||||
@Nullable
|
||||
protected View onCreateOperatorLayout(final QMUIDialog dialog, QMUIDialogView parent, Context context) {
|
||||
protected View onCreateOperatorLayout(@NonNull final QMUIDialog dialog, @NonNull QMUIDialogView parent, @NonNull Context context) {
|
||||
int size = mActions.size();
|
||||
if (size > 0) {
|
||||
TypedArray a = context.obtainStyledAttributes(null, R.styleable.QMUIDialogActionContainerCustomDef, R.attr.qmui_dialog_action_container_style, 0);
|
||||
@@ -593,7 +584,7 @@ public abstract class QMUIDialogBuilder<T extends QMUIDialogBuilder> {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
protected ConstraintLayout.LayoutParams onCreateOperatorLayoutLayoutParams(Context context) {
|
||||
protected ConstraintLayout.LayoutParams onCreateOperatorLayoutLayoutParams(@NonNull Context context) {
|
||||
ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
lp.leftToLeft = ConstraintLayout.LayoutParams.PARENT_ID;
|
||||
lp.rightToRight = ConstraintLayout.LayoutParams.PARENT_ID;
|
||||
|
||||
@@ -18,17 +18,18 @@ package com.qmuiteam.qmui.widget.dialog;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.qmuiteam.qmui.R;
|
||||
import com.qmuiteam.qmui.util.QMUIDisplayHelper;
|
||||
import com.qmuiteam.qmui.util.QMUIResHelper;
|
||||
import com.qmuiteam.qmui.util.QMUIWindowHelper;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class QMUIDialogRootLayout extends ViewGroup {
|
||||
|
||||
private QMUIDialogView mDialogView;
|
||||
@@ -39,6 +40,9 @@ public class QMUIDialogRootLayout extends ViewGroup {
|
||||
private int mInsetVer;
|
||||
private boolean mCheckKeyboardOverlay = false;
|
||||
private float mMaxPercent = 0.75f;
|
||||
private boolean isOverlayOccurEventNotified = false;
|
||||
private OverlayOccurInMeasureCallback mOverlayOccurInMeasureCallback;
|
||||
private int mLastContentInsetTop = 0;
|
||||
|
||||
|
||||
public QMUIDialogRootLayout(@NonNull Context context, @NonNull QMUIDialogView dialogView,
|
||||
@@ -73,6 +77,10 @@ public class QMUIDialogRootLayout extends ViewGroup {
|
||||
mInsetVer = insetVer;
|
||||
}
|
||||
|
||||
public void setOverlayOccurInMeasureCallback(OverlayOccurInMeasureCallback overlayOccurInMeasureCallback) {
|
||||
mOverlayOccurInMeasureCallback = overlayOccurInMeasureCallback;
|
||||
}
|
||||
|
||||
public void setCheckKeyboardOverlay(boolean checkKeyboardOverlay) {
|
||||
mCheckKeyboardOverlay = checkKeyboardOverlay;
|
||||
}
|
||||
@@ -84,11 +92,17 @@ public class QMUIDialogRootLayout extends ViewGroup {
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
int keyboardOverlayHeight = 0;
|
||||
int contentInsetVer = 0;
|
||||
if (mCheckKeyboardOverlay) {
|
||||
Rect visibleInsetRect = QMUIWindowHelper.unSafeGetWindowVisibleInsets(this);
|
||||
Rect contentInsetRect = QMUIWindowHelper.unSafeGetContentInsets(this);
|
||||
if (visibleInsetRect != null) {
|
||||
keyboardOverlayHeight = visibleInsetRect.bottom;
|
||||
}
|
||||
if (contentInsetRect != null) {
|
||||
mLastContentInsetTop = contentInsetRect.top;
|
||||
contentInsetVer = contentInsetRect.top + contentInsetRect.bottom;
|
||||
}
|
||||
}
|
||||
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
|
||||
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
|
||||
@@ -111,13 +125,24 @@ public class QMUIDialogRootLayout extends ViewGroup {
|
||||
childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(mDialogViewLp.height, MeasureSpec.EXACTLY);
|
||||
} else {
|
||||
int childMaxHeight;
|
||||
if(keyboardOverlayHeight > 0){
|
||||
childMaxHeight = Math.max(heightSize - 2 * mInsetVer - keyboardOverlayHeight, 0);
|
||||
}else{
|
||||
if (keyboardOverlayHeight > 0) {
|
||||
if (getRootView() != null && getRootView().getHeight() > 0) {
|
||||
// the overlay occurred with this height, we can't change it.
|
||||
heightSize = getRootView().getHeight();
|
||||
if (!isOverlayOccurEventNotified) {
|
||||
isOverlayOccurEventNotified = true;
|
||||
if (mOverlayOccurInMeasureCallback != null) {
|
||||
mOverlayOccurInMeasureCallback.call();
|
||||
}
|
||||
}
|
||||
}
|
||||
childMaxHeight = Math.max(heightSize - 2 * mInsetVer - keyboardOverlayHeight - contentInsetVer, 0);
|
||||
} else {
|
||||
// use maxPercent to keep dialog from being too high and calculated based on
|
||||
// screen height because height size while change to actual height when multi onMeasure.
|
||||
childMaxHeight = Math.min(heightSize - 2 * mInsetVer,
|
||||
(int)(QMUIDisplayHelper.getScreenHeight(getContext()) * mMaxPercent - 2 * mInsetVer));
|
||||
isOverlayOccurEventNotified = false;
|
||||
childMaxHeight = Math.min(heightSize - 2 * mInsetVer - contentInsetVer,
|
||||
(int) (QMUIDisplayHelper.getScreenHeight(getContext()) * mMaxPercent - 2 * mInsetVer));
|
||||
}
|
||||
if (mDialogViewLp.height == LayoutParams.MATCH_PARENT) {
|
||||
childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childMaxHeight, MeasureSpec.EXACTLY);
|
||||
@@ -132,7 +157,7 @@ public class QMUIDialogRootLayout extends ViewGroup {
|
||||
}
|
||||
// InsetVer works when keyboard overlay occurs
|
||||
setMeasuredDimension(mDialogView.getMeasuredWidth(),
|
||||
mDialogView.getMeasuredHeight() + 2 * mInsetVer + keyboardOverlayHeight);
|
||||
mDialogView.getMeasuredHeight() + 2 * mInsetVer + keyboardOverlayHeight + contentInsetVer);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -147,4 +172,20 @@ public class QMUIDialogRootLayout extends ViewGroup {
|
||||
public QMUIDialogView getDialogView() {
|
||||
return mDialogView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
// I think this is a android system bug:
|
||||
// When show keyboard In fullscreen and the content overlaps with keyboard,
|
||||
// then the mAttachInfo.mContentInset.top equals notch's height
|
||||
// but the event's y and draw position has different behavior if notch exist.
|
||||
if (mLastContentInsetTop > 0) {
|
||||
ev.offsetLocation(0, -mLastContentInsetTop);
|
||||
}
|
||||
return super.dispatchTouchEvent(ev);
|
||||
}
|
||||
|
||||
interface OverlayOccurInMeasureCallback {
|
||||
void call();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user