起因呢又是有个需求,也是自己觉得好看,很多app都有下拉选择框,就想着实现下(主要是时间空闲,如果时间少,项目急,就找现成的),先看图片:
直接上代码:
xml:
attrs:这个属性的作用是在内容较长的情况下保持底部距离
view:
package com.yinp.proapp.module.work.view;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.frameLayout;
import android.widget.RelativeLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.yinp.proapp.R;
import com.yinp.proapp.utils.AppUtils;
public class DownSelectDialogView extends frameLayout {
private int contentWidth;
private int contentHeight;
private boolean isFirstLoad = false;
private boolean isCanEnd = false;
private boolean isStarting = false;
private long duration = 400;
private Rect rectContent;
public DownSelectDialogView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public DownSelectDialogView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public DownSelectDialogView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initFirstView(attrs);
}
private frameLayout dialogContentView;
private RelativeLayout dialogBgView;
private int bottomMargin = 100;
private void initFirstView(AttributeSet attrs) {
setVisibility(GONE);
isFirstLoad = true;
TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.DownSelectDialogView);
bottomMargin = ta.getInteger(R.styleable.DownSelectDialogView_dsdvBottomMargin, bottomMargin);
ta.recycle();
dialogBgView = new RelativeLayout(getContext());
LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
dialogBgView.setLayoutParams(layoutParams);
dialogBgView.setBackgroundColor(Color.BLACK);
addView(dialogBgView, 0);
dialogContentView = new frameLayout(getContext());
LayoutParams layoutParams2 = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
layoutParams2.bottomMargin = AppUtils.dpToPx(getContext(), bottomMargin);
dialogContentView.setLayoutParams(layoutParams2);
addView(dialogContentView, 1);
}
public void mAddView(View child) {
if (dialogContentView != null) {
dialogContentView.addView(child);
}
}
private String mFlag = "";
public void mAddView(View child, String flag) {
if (child != null && dialogContentView != null) {
boolean isDiff = mFlag.equals(flag);
if (!isDiff) {
mRemoveView();
dialogContentView.addView(child);
}
startAnimations(isDiff);
mFlag = flag;
}
}
public void mRemoveView() {
if (dialogContentView != null && dialogContentView.getChildCount() > 0) {
dialogContentView.removeAllViews();
}
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (getChildCount() != 2) {
return;
}
if (isFirstLoad) {
isFirstLoad = false;
rectContent = new Rect();
} else {
contentWidth = dialogContentView.getWidth();
contentHeight = dialogContentView.getHeight();
rectContent.left = dialogContentView.getLeft();
rectContent.top = dialogContentView.getTop();
rectContent.right = dialogContentView.getRight();
rectContent.bottom = dialogContentView.getBottom();
dialogContentView.layout(0, 0, contentWidth, contentHeight);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (!rectContent.contains((int) event.getX(), (int) event.getY())) {
endAnimation();
}
break;
}
//必须对点击事件进行拦截
return true;
}
public void startAnimations(boolean isDiff) {
if (isStarting || !isEnd) {
return;
}
setVisibility(VISIBLE);
if (!isDiff) {
dialogContentView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
contentHeight = dialogContentView.getHeight();
start();
getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
} else {
start();
}
}
private void start() {
//清理动画
dialogContentView.clearAnimation();
dialogBgView.clearAnimation();
isCanEnd = false;
isStarting = true;
ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(dialogBgView, "alpha", 0, 0.4f);
ObjectAnimator translationAnimator = ObjectAnimator.ofFloat(dialogContentView, "translationY", -contentHeight * 1.0f, 0f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(alphaAnimator, translationAnimator);
animatorSet.setDuration(duration);
animatorSet.start();
if (animatorSet.isStarted()) {
isCanEnd = true;
}
}
private boolean isEnd = true;
public void endAnimation() {
//目的时判断当前是否有开启动画,有才允许关闭动画
if (!isCanEnd) {
return;
}
//清理动画
dialogContentView.clearAnimation();
dialogBgView.clearAnimation();
isCanEnd = false;
isEnd = false;
isStarting = false;
ObjectAnimator alphaOb = ObjectAnimator.ofFloat(dialogBgView, "alpha", 0.4f, 0f);
ObjectAnimator translationYOb = ObjectAnimator.ofFloat(dialogContentView, "translationY", 0f, 1.0f * (-contentHeight));
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(alphaOb, translationYOb);
animatorSet.setDuration(duration);
animatorSet.start();
animatorSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
setVisibility(GONE);
isEnd = true;
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
}
private OnDialogOpenListener onDialogOpenListener;
public interface OnDialogOpenListener {
void onDialogOpen(boolean isOpen);
}
public void setOnDialogOpenListener(OnDialogOpenListener onDialogOpenListener) {
this.onDialogOpenListener = onDialogOpenListener;
}
public void setDuration(long duration) {
this.duration = duration;
}
public boolean isStarting() {
return isStarting;
}
}
activity:
public class DownSelectDialogActivity extends AppbaseFragmentActivity{ View viewOne; View viewTwo; //onCreate调用的方法 @Override protected void initViews() { setStatusBarHeight(StatusBarUtil.getStatusBarHeight(mContext)); bd.btnOne.setOnClickListener(v -> { bd.dsdDialog.mAddView((viewOne == null ? initViewOne() : viewOne), "viewOne"); }); bd.btnTwo.setOnClickListener(v -> { bd.dsdDialog.mAddView((viewTwo == null ? initViewTwo() : viewTwo), "viewTwo"); }); // dsvView.endAnimation();可以通过调用主动结束 } private View initViewOne() { viewOne = LayoutInflater.from(this).inflate(R.layout.layout_one_one, null); //可处理逻辑 return viewOne; } private View initViewTwo() { viewTwo = LayoutInflater.from(this).inflate(R.layout.layout_one_two, null); //可处理逻辑 return viewTwo; } }
直接拿来就可以用,没有做所有情况的适配,自己用可以修改。因为是模拟的弹窗效果,实际上是布局,所以需要在layout中添加它的布局。还有另外一种方案使用poupwindow
,但是popupWindow.setAnimationStyle(R.style.popwin_anim_style);只能这样使用这种动画设置,就是透明度变化,而不能做到根据位置来实现平移动画,所以放弃了



