BottomSheetDialogFragment是可以上下滑動退出的dialogFragment御毅,里面就是behavior起到了作用漂洋,感興趣的可以去了解了解每界,我這里記錄一下寫過的demo捷泞。仔細觀察抖音的評論列表声搁,它底部的請輸入框其實是個Textview黑竞,點擊后才彈出輸入的dialog彈窗,如果不這樣做疏旨,會有一個問題很魂,就是列表往下滑的時候,底部的布局并沒有跟著移動檐涝。當然遏匆,我們也能做一個recycleview的底部條目為輸入框法挨,這里我采取了點擊彈出真正的對話框的方式。好幅聘,下面直接上代碼凡纳。
評論列表
列表fragment
public class CommendMsgDialogFragment extends BottomSheetDialogFragment {
private RecyclerView mRecyclerView;
private CommendAdapter mCommendAdapter;
private FragmentCommendMsgDialogBinding mBinding;
private String mUniquekey;
private CommendInputDialogFragment mCommendInputDialog;
public CommendMsgDialogFragment() {
// Required empty public constructor
}
public static CommendMsgDialogFragment newInstance(String uniquekey) {
CommendMsgDialogFragment fragment = new CommendMsgDialogFragment();
Bundle args = new Bundle();
args.putString("uniquekey",uniquekey);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//設置背景透明,才能顯示出layout中諸如圓角的布局帝蒿,否則會有白色底(框)
setStyle(BottomSheetDialogFragment.STYLE_NORMAL, R.style.CustomBottomSheetDialogTheme);
if (getArguments() != null) {
mUniquekey = getArguments().getString("uniquekey");
mUniquekey = "c322b12d56a3125e73e7b2978ff846c0";
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
mBinding = DataBindingUtil.inflate(getLayoutInflater(), R.layout.fragment_commend_msg_dialog, container, false);
return mBinding.getRoot();
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
Window window = getDialog().getWindow();
window.requestFeature(Window.FEATURE_NO_TITLE);
super.onActivityCreated(savedInstanceState);
//設置背景為透明
window.setWindowAnimations(R.style.AnimBottom);
window.setBackgroundDrawable(ContextCompat.getDrawable(getContext(), android.R.color.transparent));
//去除陰影
window.setGravity(Gravity.BOTTOM);
WindowManager.LayoutParams layoutParams = window.getAttributes();
layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
layoutParams.dimAmount = 0.1f;
window.setAttributes(layoutParams);
getDialog().setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
if(mOnDisMissCallBack != null){
mOnDisMissCallBack.onDismiss();
}
dismissAllowingStateLoss();
}
});
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mRecyclerView = mBinding.mBottomSheet;
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
mCommendAdapter = new CommendAdapter();
mRecyclerView.setAdapter(mCommendAdapter);
mBinding.mTextView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showInputDialog();
}
});
mBinding.mTvSend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
savePost();
}
});
initData();
}
private void showInputDialog() {
if(mCommendInputDialog == null){
mCommendInputDialog = CommendInputDialogFragment.newInstance(mUniquekey,mBinding.mTextView.getText().toString());
mCommendInputDialog.setOnDisMissCallBack(new CommendInputDialogFragment.OnDisMissCallBack() {
@Override
public void onDismiss() {
mCommendInputDialog = null;
}
@Override
public void saveCommend() {
savePost();
}
@Override
public void onCommendTextChanged(String contend) {
mBinding.mTextView.setText(contend);
}
});
mCommendInputDialog.show(getChildFragmentManager(),mCommendInputDialog.getTag());
}
}
/**
* 根據(jù)key值獲取他的所有評論荐糜,按時間排序
*/
private void initData() {
if (BmobUser.isLogin()) {
BmobQuery<CommentBean> query = new BmobQuery<>();
query.addWhereEqualTo("uniquekey", mUniquekey);
query.order("-updatedAt");
//包含作者信息
query.include("user");
query.findObjects(new FindListener<CommentBean>() {
@Override
public void done(List<CommentBean> object, BmobException e) {
if (e == null) {
mCommendAdapter.refreshList(object);
} else {
Toast.makeText(App.getInstance(), "請求失敗:"+e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
});
} else {
Toast.makeText(App.getInstance(), "請先登錄~", Toast.LENGTH_SHORT).show();
}
}
/**
* 添加一對一關聯(lián),當前用戶發(fā)布帖子
*/
private void savePost() {
String content = mBinding.mTextView.getText().toString();
if (TextUtils.isEmpty(content)) {
Toast.makeText(App.getInstance(), "內容不能為空", Toast.LENGTH_SHORT).show();
return;
}
if (BmobUser.isLogin()) {
CommentBean post = new CommentBean();
post.setContent(content);
post.setUniquekey(mUniquekey);
//添加一對一關聯(lián)葛超,用戶關聯(lián)帖子
post.setUser(BmobUser.getCurrentUser(User.class));
post.save(new SaveListener<String>() {
@Override
public void done(String s, BmobException e) {
if (e == null) {
Toast.makeText(App.getInstance(), "評論成功~", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(App.getInstance(), "評論失敗:" + e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
});
} else {
Toast.makeText(App.getInstance(), "請先登錄~", Toast.LENGTH_SHORT).show();
}
}
public interface OnDisMissCallBack{
void onDismiss();
}
private OnDisMissCallBack mOnDisMissCallBack;
public void setOnDisMissCallBack(OnDisMissCallBack mOnDisMissCallBack) {
this.mOnDisMissCallBack = mOnDisMissCallBack;
}
}
這里的initData方法是數(shù)據(jù)源狞尔,我這里用的是bmbo第三方sdk,他可以把數(shù)據(jù)存到他們的數(shù)據(jù)庫中巩掺,并且可以用sql代碼查詢偏序,少量的數(shù)據(jù)是免費的,適合學生黨來寫畢業(yè)論文胖替。
然后是布局
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:fitsSystemWindows="true">
<data>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context=".fragments.dialogfragments.CommendMsgDialogFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/mBottomSheet"
android:layout_width="match_parent"
android:layout_height="400dp"
android:orientation="vertical"
app:behavior_hideable="true"
app:behavior_peekHeight="66dp"
android:paddingBottom="50dp"
app:layout_behavior="@string/bottom_sheet_behavior"
android:background="@drawable/bg_round15_top_white"
app:layout_constraintTop_toTopOf="parent"></androidx.recyclerview.widget.RecyclerView>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/storke_line_1dp_dcdcdc"
android:layout_gravity="bottom"
app:layout_constraintBottom_toBottomOf="parent">
<TextView
android:id="@+id/mTvSend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="發(fā)送"
android:textSize="16sp"
android:textColor="@color/write"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:layout_alignParentRight="true"
android:layout_marginRight="15dp"
android:layout_centerVertical="true"
android:background="@drawable/send_commend_bg" />
<TextView
android:id="@+id/mTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="35dp"
android:background="@drawable/et_search_bg"
android:layout_toLeftOf="@id/mTvSend"
android:layout_marginRight="15dp"
android:layout_centerVertical="true"
android:layout_marginLeft="15dp"
android:text=""
android:gravity="center_vertical"
android:hint="發(fā)個評論研儒,說不定能火"
android:paddingTop="3dp"
android:paddingBottom="3dp"
android:maxLines="2"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:textColor="@color/ff333333"
android:textSize="14sp" />
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
adapter代碼
public class CommendAdapter extends RecyclerView.Adapter<CommendAdapter.ViewHolder> {
private List<CommentBean> list = new ArrayList<>();
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.commend_item_layout, parent, false);
CommendItemLayoutBinding bind = DataBindingUtil.bind(view);
return new ViewHolder(bind);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
CommentBean commentBean = list.get(position);
if(commentBean != null){
if(commentBean.getUser().getAvatar() != null){
ImageLoader.getInstance().loadCircleImage(holder.mBinding.mIvHead.getContext(),
commentBean.getUser().getAvatar().getUrl(),R.mipmap.default_head_img,holder.mBinding.mIvHead);
}
holder.mBinding.mTvNickName.setText(commentBean.getUser().getNickname());
holder.mBinding.mTvContent.setText(commentBean.getContent());
}
}
@Override
public int getItemCount() {
return list.size();
}
public void refreshList(List<CommentBean> object) {
this.list.clear();
this.list.addAll(object);
notifyDataSetChanged();
}
public class ViewHolder extends RecyclerView.ViewHolder {
CommendItemLayoutBinding mBinding;
public ViewHolder(@NonNull View itemView) {
super(itemView);
}
public ViewHolder(@NonNull CommendItemLayoutBinding bind) {
super(bind.getRoot());
mBinding = bind;
}
}
}
然后是條目布局
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="10dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/mIvHead"
android:layout_width="50dp"
android:layout_height="50dp"
android:src="@mipmap/default_head_img" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:orientation="vertical">
<TextView
android:id="@+id/mTvNickName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="昵稱"
android:textColor="@color/ff333333"
android:textSize="18sp" />
<TextView
android:id="@+id/mTvContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:textColor="@color/ff949494"
android:textSize="14sp"
android:layout_marginTop="5dp" />
</LinearLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:background="@color/f5f5f5" />
</LinearLayout>
</layout>
很簡單的布局
好當我們點擊底部的輸入框時,彈出真正的輸入彈窗独令。
mBinding.mTextView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showInputDialog();
}
});
private void showInputDialog() {
if(mCommendInputDialog == null){
mCommendInputDialog = CommendInputDialogFragment.newInstance(mUniquekey,mBinding.mTextView.getText().toString());
mCommendInputDialog.setOnDisMissCallBack(new CommendInputDialogFragment.OnDisMissCallBack() {
@Override
public void onDismiss() {
mCommendInputDialog = null;
}
@Override
public void saveCommend() {
savePost();
}
@Override
public void onCommendTextChanged(String contend) {
mBinding.mTextView.setText(contend);
}
});
mCommendInputDialog.show(getChildFragmentManager(),mCommendInputDialog.getTag());
}
}
接下來上輸入框彈窗的代碼
輸入框
public class CommendInputDialogFragment extends DialogFragment {
private FragmentCommendInputDialogBinding mBinding;
private int mAllowableErrorHeight;
public CommendInputDialogFragment() {
// Required empty public constructor
}
private String mUniquekey;
private String mContent;
private int mLastDiff = 0;
public static final String UNIQUEKEY = "uniquekey";
public static final String CONTENT = "content";
public static CommendInputDialogFragment newInstance(String uniquekey,String content) {
CommendInputDialogFragment fragment = new CommendInputDialogFragment();
Bundle args = new Bundle();
args.putString(UNIQUEKEY, uniquekey);
args.putString(CONTENT, content);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mUniquekey = getArguments().getString(UNIQUEKEY);
mUniquekey = "c322b12d56a3125e73e7b2978ff846c0";
mContent = getArguments().getString(CONTENT);
}
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
Window window = getDialog().getWindow();
super.onActivityCreated(savedInstanceState);
getDialog().setCancelable(true);
getDialog().setCanceledOnTouchOutside(true);
//設置背景為透明
window.setWindowAnimations(R.style.AnimBottom);
window.setBackgroundDrawable(ContextCompat.getDrawable(getContext(), android.R.color.transparent));
//去除陰影
window.setGravity(Gravity.BOTTOM);
WindowManager.LayoutParams layoutParams = window.getAttributes();
layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
layoutParams.dimAmount = 0.5f;
window.setAttributes(layoutParams);
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE|WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
getDialog().setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
dismissDialog();
}
});
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
mBinding = DataBindingUtil.bind(inflater.inflate(R.layout.fragment_commend_input_dialog, container, false));
return mBinding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mBinding.mTvSend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String content = mBinding.mEditText.getText().toString();
if (TextUtils.isEmpty(content)) {
Toast.makeText(App.getInstance(), "內容不能為空", Toast.LENGTH_SHORT).show();
return;
}
if (mOnDisMissCallBack != null) {
mOnDisMissCallBack.saveCommend();
}
dismissDialog();
}
});
mBinding.mEditText.setFocusable(true);
mBinding.mEditText.setFocusableInTouchMode(true);
mBinding.mEditText.requestFocus();
mBinding.mEditText.postDelayed(new Runnable() {
@Override
public void run() {
InputMethodManager imm = (InputMethodManager) getContext()
.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(0, InputMethodManager.SHOW_FORCED);
Rect r = new Rect();
//獲取當前界面可視部分
getActivity().getWindow().getDecorView().getRootView().getWindowVisibleDisplayFrame(r);
//獲取屏幕的高度
int screenHeight = getActivity().getWindow().getDecorView().getRootView().getHeight();
//此處就是用來獲取鍵盤的高度的端朵, 在鍵盤沒有彈出的時候 此高度為0 鍵盤彈出的時候為一個正數(shù)
mAllowableErrorHeight = screenHeight - r.bottom;
setOnKeyBordListener();
}
},100);
mBinding.mEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
String content = mBinding.mEditText.getText().toString();
if(mOnDisMissCallBack != null){
mOnDisMissCallBack.onCommendTextChanged(content);
}
}
@Override
public void afterTextChanged(Editable s) {
}
});
//設置已經填過的文字,以及移動光標
mBinding.mEditText.setText(mContent);
if(!TextUtils.isEmpty(mContent) && mContent.length() > 0){
mBinding.mEditText.setSelection(mContent.length());
}
}
private void setOnKeyBordListener() {
getActivity().getWindow().getDecorView().addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
try {
Rect r = new Rect();
//獲取當前界面可視部分
getActivity().getWindow().getDecorView().getRootView().getWindowVisibleDisplayFrame(r);
//獲取屏幕的高度
int screenHeight = getActivity().getWindow().getDecorView().getRootView().getHeight();
//此處就是用來獲取鍵盤的高度的燃箭, 在鍵盤沒有彈出的時候 此高度為0 鍵盤彈出的時候為一個正數(shù)
int heightDifference = screenHeight - r.bottom;
if (heightDifference > mAllowableErrorHeight && mLastDiff >= 0) {
//開軟鍵盤
} else {
//關閉軟鍵盤
dismissDialog();
}
mLastDiff = heightDifference;
}catch (Exception e){
e.printStackTrace();
}
}
});
// mBinding.mRoot.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
// @Override
// public void onLayoutChange(View view, int i, int i1, int i2, int i3, int i4, int i5, int i6, int i7) {
// Rect r = new Rect();
// //獲取當前界面可視部分
// getActivity().getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
// //獲取屏幕的高度
// int screenHeight = getActivity().getWindow().getDecorView().getRootView().getHeight();
//
// //此處就是用來獲取鍵盤的高度的冲呢, 在鍵盤沒有彈出的時候 此高度為0 鍵盤彈出的時候為一個正數(shù)
// int heightDifference = screenHeight - r.bottom;
// if (heightDifference <= mAllowableErrorHeight && mLastDiff >= 0) {
// //開軟鍵盤
// } else {
// //關閉軟鍵盤
// dismissDialog();
// }
// Log.d("yanjin","heightDifference = "+heightDifference+" mLastDiff="+mLastDiff);
// mLastDiff = heightDifference;
// }
// });
}
private void dismissDialog() {
if (mOnDisMissCallBack != null) {
mOnDisMissCallBack.onDismiss();
}
dismissAllowingStateLoss();
}
@Override
public void dismiss() {
super.dismiss();
mLastDiff = 0;
}
public interface OnDisMissCallBack {
void onDismiss();
void saveCommend();
void onCommendTextChanged(String contend);
}
private OnDisMissCallBack mOnDisMissCallBack;
public void setOnDisMissCallBack(OnDisMissCallBack mOnDisMissCallBack) {
this.mOnDisMissCallBack = mOnDisMissCallBack;
}
}
布局
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
</data>
<FrameLayout
android:id="@+id/mRoot"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context=".adapter.CommendInputDialogFragment">
<RelativeLayout
android:id="@+id/rldlgview"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/storke_line_1dp_dcdcdc">
<TextView
android:id="@+id/mTvSend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="發(fā)送"
android:textSize="16sp"
android:textColor="@color/write"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:layout_alignParentRight="true"
android:layout_marginRight="15dp"
android:layout_centerVertical="true"
android:background="@drawable/send_commend_bg" />
<EditText
android:id="@+id/mEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="35dp"
android:background="@drawable/et_search_bg"
android:layout_toLeftOf="@id/mTvSend"
android:layout_marginRight="15dp"
android:layout_centerVertical="true"
android:layout_marginLeft="15dp"
android:text=""
android:hint="發(fā)個評論,說不定能火"
android:paddingTop="3dp"
android:paddingBottom="3dp"
android:maxLines="2"
android:gravity="center_vertical"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:textColor="@color/ff333333"
android:textSize="14sp" />
</RelativeLayout>
</FrameLayout>
</layout>
仔細觀察抖音招狸,他是點擊彈窗外部敬拓,隱藏dialog和軟鍵盤、點擊物理返回鍵隱藏dialog裙戏、點擊軟鍵盤的收起按鈕隱藏dialog乘凸。這三點很重要
//解決點擊彈窗外部,隱藏dialog和軟鍵盤
getDialog().setCanceledOnTouchOutside(true);
而點擊物理返回鍵隱藏dialog累榜、點擊軟鍵盤的收起按鈕隱藏dialog這兩個其實都只要監(jiān)聽軟鍵盤隱藏就可以了营勤,那怎么做呢?看下面的代碼壹罚。
private void setOnKeyBordListener() {
mBinding.rldlgview.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View view, int i, int i1, int i2, int i3, int i4, int i5, int i6, int i7) {
Rect r = new Rect();
//獲取當前界面可視部分
getActivity().getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
//獲取屏幕的高度
int screenHeight = getActivity().getWindow().getDecorView().getRootView().getHeight();
//此處就是用來獲取鍵盤的高度的葛作, 在鍵盤沒有彈出的時候 此高度為0 鍵盤彈出的時候為一個正數(shù)
int heightDifference = screenHeight - r.bottom;
if (heightDifference <= 0 && mLastDiff >= 0) {
//開軟鍵盤
} else {
//關閉軟鍵盤
dismissDialog();
}
mLastDiff = heightDifference;
}
});
}
好,寫完收工猖凛。
哦赂蠢,對了怎么調起彈窗呢?看如下代碼即可:
if(mCommendMsgDialogFragment == null){
mCommendMsgDialogFragment = CommendMsgDialogFragment.newInstance(uniquekey);
mCommendMsgDialogFragment.setOnDisMissCallBack(new CommendMsgDialogFragment.OnDisMissCallBack() {
@Override
public void onDismiss() {
mCommendMsgDialogFragment = null;
}
});
mCommendMsgDialogFragment.show(getSupportFragmentManager(), mCommendMsgDialogFragment.getTag());
}