package com.zdj.zdj_library.widget;
import android.app.Dialog;
import android.content.Context;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.PopupWindow;
import androidx.annotation.NonNull;
import com.zdj.zdj_library.R;
import com.zdj.zdj_library.util.UiUtils;
import com.zdj.zdj_library.view.TitleBar;
/**
* <pre>
* author : zhangdj
* time : 2021/07/12
* desc : 原因弹框
* 注:该弹框支持跟随手指向下滑动
* 实现思路:自定义Dialog,重写onTouchEvent。在down的时候记录y,滑动的时候计算出滑动距离。scrollBy控制view(decorView,通过getWindow().getDecorView()得到dialog的decorView)的滑动。
* 确保view不能往上滑动溢出,所以控制view.getScrollY大于0的时候重置。手指抬起的时候判断滑动方向如果是向下并且超过四分之一,隐藏dialog,然后重置view的内容的位置。
* 通过改变mScrollY来变化view的位置,实际上view本身并没有发生移动,移动的是view的内容。view的内容和view本身的横向纵向距离就是mScrollX和mScrollY的值。
* </pre>
*/
public class ReasonDialog extends Dialog {
Context context;
View view;
public ReasonDialog(@NonNull Context context, int themeResId) {
super(context, themeResId);
setContentView(R.layout.dialog_reason);
Window window = getWindow();
WindowManager.LayoutParams layoutParams = window.getAttributes();
layoutParams.width = layoutParams.MATCH_PARENT;
layoutParams.height = (int) (UiUtils.getHeight(context) * 0.6);
window.setAttributes(layoutParams);
window.setGravity(Gravity.BOTTOM);
this.context = context;
view = window.getDecorView();
}
public void init(final String title, final Callback callback) {
TitleBar titleBar = findViewById(R.id.titleBar);
titleBar.setViewVisible(false, false, false, true, true)
.setTitleTvText(title)
.setLeftTvText(this.context.getString(R.string.cancel))
.setRightTvText(this.context.getString(R.string.confirm))
.setLeftTvTextColor(this.context.getResources().getColor(R.color.light_gray_6))
.setRightTvTextColor(this.context.getResources().getColor(R.color.blue));
final EditText et_reason = findViewById(R.id.et_reason);
UiUtils.setEditTextHintTextSize("200个字以内", 14, et_reason);
titleBar.setClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (v.getId() == R.id.tv_left) {
dismiss();
} else if (v.getId() == R.id.tv_right) {
dismiss();
if (callback != null) {
String reason = et_reason.getText().toString();
if (reason == null) {
reason = "";
}
callback.confirm(reason);
}
}
}
});
}
float startY;
float moveY;
@Override
public boolean onTouchEvent(@NonNull MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
moveY = event.getY() - startY;
//传正值往上滑动,传负值往下滑动。这个在view的scrollBy、scrollTo方法源码解析里面已经分析过。
view.scrollBy(0, -(int)moveY);
startY = event.getY();
if (view.getScrollY() > 0) {
view.scrollTo(0, 0);
}
break;
case MotionEvent.ACTION_UP:
if (view.getScrollY() < -this.getWindow().getAttributes().height / 4) {
this.dismiss();
}
view.scrollTo(0,0);
break;
}
return super.onTouchEvent(event);
}
public Callback callback;
public interface Callback {
void confirm(String reason);
}
}
空闲之余,记录一下。代码里面很清晰,并且有注释。直接看代码即可。