DialogFragment或者Dialog在某些機型上寬高設定無效或者不適配問題的解決
Dialog可以說是一個專案中的必用控制元件了,但是既然Google推薦用DialogFragment來替代Dialog,那我們就改用DialogFragment吧,話不多說,寫一個最簡單常見的螢幕中間彈出的DialogFragment,下面是java程式碼:
public class CenterTipDialogFragment extends DialogFragment {
@BindView(R.id.tv_title)
TextView tvTitle;
@BindView(R.id.tv_content)
TextView tvContent;
@BindView (R.id.tv_left)
TextView tvLeft;
@BindView(R.id.tv_right)
TextView tvRight;
private Unbinder unbinder;
private OnClickListener mOnClickListener;
private String mTitle;
private String mContent;
private String mLeftText;
private String mRightText;
private View mContentView;
public interface OnClickListener {
void onLeftBtnClick();
void onRightBtnClick();
}
public static CenterTipDialogFragment newInstance(String title,String content,String leftText,String rightText){
CenterTipDialogFragment fragment = new CenterTipDialogFragment();
Bundle bundle = new Bundle();
bundle.putString("title", title);
bundle.putString("content", content);
bundle.putString("leftText", leftText);
bundle.putString("rightText", rightText);
fragment.setArguments(bundle);
return fragment;
}
public CenterTipDialogFragment setClickListener(OnClickListener listener){
mOnClickListener = listener;
return this;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
mContentView = inflater.inflate(R.layout.dlg_center_tip, container, true);
unbinder = ButterKnife.bind(this, view);
return mContentView;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams();
layoutParams.width = (int) (getResources().getDisplayMetrics().widthPixels * 0.8);
initData();
}
private void initData() {
Bundle bundle = getArguments();
if (bundle != null){
mTitle = bundle.getString("title");
mContent = bundle.getString("content");
mLeftText = bundle.getString("leftText");
mRightText = bundle.getString("rightText");
}
if (TextUtils.isEmpty(mTitle)) {
tvTitle.setVisibility(View.GONE);
} else {
tvTitle.setVisibility(View.VISIBLE);
tvTitle.setText(mTitle);
}
if (TextUtils.isEmpty(mContent)) {
tvContent.setVisibility(View.GONE);
} else {
tvContent.setVisibility(View.VISIBLE);
tvContent.setText(mContent);
}
if (TextUtils.isEmpty(mLeftText)) {
tvLeft.setVisibility(View.GONE);
} else {
tvLeft.setVisibility(View.VISIBLE);
tvLeft.setText(mLeftText);
}
if (TextUtils.isEmpty(mRightText)) {
tvRight.setVisibility(View.GONE);
} else {
tvRight.setVisibility(View.VISIBLE);
tvRight.setText(mRightText);
}
tvLeft.setOnClickListener(v -> {
if (mOnClickListener != null) {
mOnClickListener.onLeftBtnClick();
CenterTipDialogFragment.this.dismiss();
}
});
tvRight.setOnClickListener(v -> {
if (mOnClickListener != null) {
mOnClickListener.onRightBtnClick();
CenterTipDialogFragment.this.dismiss();
}
});
}
@Override
public void onDestroy() {
unbinder.unbind();
super.onDestroy();
}
}
然後是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/ll_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_radius_white"
android:divider="@drawable/horizontal_grey_line"
android:orientation="vertical"
android:showDividers="middle">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="30dp"
android:textColor="@color/color_222222"
android:textSize="16sp"
android:textStyle="bold"
tools:text="稽核未通過" />
<TextView
android:id="@+id/tv_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="40dp"
android:textColor="@color/color_222222"
android:textSize="16sp"
tools:text="圖片不清晰,稽核未通過" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="@drawable/vertical_grey_line"
android:orientation="horizontal"
android:showDividers="middle">
<TextView
android:id="@+id/tv_left"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:paddingVertical="13dp"
android:textColor="@color/color_037CFF"
android:textSize="14sp"
tools:text="取消" />
<TextView
android:id="@+id/tv_right"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:paddingVertical="13dp"
android:textColor="@color/color_037CFF"
android:textSize="14sp"
tools:text="重新認證" />
</LinearLayout>
</LinearLayout>
程式碼很簡單,和寫fragment幾乎一樣,DialogFragment也是繼承的Fragment,只不過加了Dialog的一些特性。執行程式碼,效果如下圖:
嗯,是不是很簡單?但是,當我換個手機執行,馬上出現問題,換成vivo手機執行如下圖:
What?上面多出來的部分和四個角的詭異圓角是什麼鬼?馬上換成Dialog試了一下,結果還是這樣。然後我開始懷疑是我佈局檔案有問題,可能vivo系統的Dialog不能自適應寬高,那麼就給佈局檔案固定寬高,試了好幾種寬高值還是沒解決,而且如果佈局檔案寫死了寬高,那麼如果標題或者內容字數多了就顯示不下了,所以不能寫死。因為對Dialog比DialogFragment熟悉,所以就開始現在Dialog中嘗試解決,首先給Dialog加一個自定義的透明背景style,
<style name="TransparentDialog" parent="@android:style/Theme.Dialog">
<!-- 背景透明 -->
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowContentOverlay">@null</item>
<!-- 浮於Activity之上 -->
<item name="android:windowIsFloating">true</item>
<!-- 邊框 -->
<item name="android:windowFrame">@null</item>
<!-- Dialog以外的區域模糊效果 -->
<item name="android:backgroundDimEnabled">true</item>
<!-- 無標題 -->
<item name="android:windowNoTitle">true</item>
<!-- 半透明 -->
<item name="android:windowIsTranslucent">true</item>
</style>
執行,無效!程式碼中重新設定contentView的寬高:
ViewGroup.LayoutParams layoutParams = contentView.getLayoutParams();
layoutParams.width = (int) (activity.getResources().getDisplayMetrics().widthPixels * 0.8);
layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
contentView.setLayoutParams(layoutParams);
執行,依然無效!靜下心來好好分析吧,看現象好像是我的contentView加入到Dialog中的時候,Dialog的最根佈局針對contentView做了處理,導致我後面重新對contentView設定layoutParams無效,那把這段程式碼放到setContentView之前試試,結果會崩潰,因為contentView.getLayoutParams()會返回null。那自己new一個layoutParams,
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams((int) (activity.getResources().getDisplayMetrics().widthPixels * 0.8),
ViewGroup.LayoutParams.WRAP_CONTENT);
contentView.setLayoutParams(layoutParams);
dialog.setContentView(contentView);
然後效果如下:
嗯,終於有所改變,看來快解決了,加油。看目前這個現象,既然對contentView設定layoutParams不行,那就對子控制元件設定,我先是對xml檔案的根佈局,就是上面xml裡的最外層的Linearlayout設定layoutParams,無效!這樣應該和對contentView設定是一樣的。那就在外面再包一層FramLayout,執行,正常了!然後再試試之前本來就顯示正常的手機,也是好的。到此,問題解決!然後把解決思路用回到DialogFragment,同樣問題解決了。Dialog的程式碼就不貼了,下面是DialogFragment的完整的程式碼:
public class CenterTipDialogFragment extends DialogFragment {
@BindView(R.id.tv_title)
TextView tvTitle;
@BindView(R.id.tv_content)
TextView tvContent;
@BindView(R.id.tv_left)
TextView tvLeft;
@BindView(R.id.tv_right)
TextView tvRight;
@BindView(R.id.ll_main)
LinearLayout mRootLayout;
private Unbinder unbinder;
private OnClickListener mOnClickListener;
private String mTitle;
private String mContent;
private String mLeftText;
private String mRightText;
public interface OnClickListener {
void onLeftBtnClick();
void onRightBtnClick();
}
public static CenterTipDialogFragment newInstance(String title,String content,String leftText,String rightText){
CenterTipDialogFragment fragment = new CenterTipDialogFragment();
Bundle bundle = new Bundle();
bundle.putString("title", title);
bundle.putString("content", content);
bundle.putString("leftText", leftText);
bundle.putString("rightText", rightText);
fragment.setArguments(bundle);
return fragment;
}
public CenterTipDialogFragment setClickListener(OnClickListener listener){
mOnClickListener = listener;
return this;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.dlg_center_tip, container, true);
//下面這兩行程式碼是關鍵,和Dialog設定背景透明和無標題的自定義style是同樣的效果
getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
unbinder = ButterKnife.bind(this, view);
return view;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//這裡也是關鍵,mRootLayout是xml檔案中倒數第二層的layout,而非最外層的layout
ViewGroup.LayoutParams layoutParams = mRootLayout.getLayoutParams();
layoutParams.width = (int) (getResources().getDisplayMetrics().widthPixels * 0.8);
initData();
}
private void initData() {
Bundle bundle = getArguments();
if (bundle != null){
mTitle = bundle.getString("title");
mContent = bundle.getString("content");
mLeftText = bundle.getString("leftText");
mRightText = bundle.getString("rightText");
}
if (TextUtils.isEmpty(mTitle)) {
tvTitle.setVisibility(View.GONE);
} else {
tvTitle.setVisibility(View.VISIBLE);
tvTitle.setText(mTitle);
}
if (TextUtils.isEmpty(mContent)) {
tvContent.setVisibility(View.GONE);
} else {
tvContent.setVisibility(View.VISIBLE);
tvContent.setText(mContent);
}
if (TextUtils.isEmpty(mLeftText)) {
tvLeft.setVisibility(View.GONE);
} else {
tvLeft.setVisibility(View.VISIBLE);
tvLeft.setText(mLeftText);
}
if (TextUtils.isEmpty(mRightText)) {
tvRight.setVisibility(View.GONE);
} else {
tvRight.setVisibility(View.VISIBLE);
tvRight.setText(mRightText);
}
tvLeft.setOnClickListener(v -> {
if (mOnClickListener != null) {
mOnClickListener.onLeftBtnClick();
CenterTipDialogFragment.this.dismiss();
}
});
tvRight.setOnClickListener(v -> {
if (mOnClickListener != null) {
mOnClickListener.onRightBtnClick();
CenterTipDialogFragment.this.dismiss();
}
});
}
@Override
public void onDestroy() {
unbinder.unbind();
super.onDestroy();
}
}
xml檔案:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_radius_white">
<LinearLayout
android:id="@+id/ll_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="@drawable/horizontal_grey_line"
android:orientation="vertical"
android:showDividers="middle">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="30dp"
android:textColor="@color/color_222222"
android:textSize="16sp"
android:textStyle="bold"
tools:text="稽核未通過" />
<TextView
android:id="@+id/tv_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="40dp"
android:textColor="@color/color_222222"
android:textSize="16sp"
tools:text="圖片不清晰,稽核未通過" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="@drawable/vertical_grey_line"
android:orientation="horizontal"
android:showDividers="middle">
<TextView
android:id="@+id/tv_left"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:paddingVertical="13dp"
android:textColor="@color/color_037CFF"
android:textSize="14sp"
tools:text="取消" />
<TextView
android:id="@+id/tv_right"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:paddingVertical="13dp"
android:textColor="@color/color_037CFF"
android:textSize="14sp"
tools:text="重新認證" />
</LinearLayout>
</LinearLayout>
</FrameLayout>
最後吐槽一下,android適配確實是件讓人頭疼的事。