Android 自定义底部弹窗

今天看了一个简单而实用的Demo所以特地到这里写个帖子,进行一些总结。第一这个技术点算是很常用的,当然我也有几种方法进行实现,但是自认没有这个简单,复用性也没有这个高。

那么进入正题,就像题目写的没错就是自定义底部弹窗。我那之前是使用PopWindow这个算是正统的使用方法,当然你如果不太熟悉PopWindow,那么你还可以用一个比较讨巧的方法,就是定义一个背景为半透明黑色的Activity,就可以了。然后两个Activity进行数据交互。总之都可以实现。但是今天讲的是既不使用PopWindow也不使用Activity,而是使用一个类,注意不是自定义View。

所以这也正是我认为这个框架,设计的巧妙和试用的地方。你只需要在你需要弹出窗口的Activity或者Fragment新建一个这个对象就可以了。
废话不多说,直接上代码。顺便我把我的心得和注释一起放出来。供大家一起欣赏。

首先看一下主要的方法类

//不是自定义View姑且称之为Panel吧
public class BottomPopPanel {

    private Context context;
    private final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.BOTTOM);
    protected ViewGroup contentContainer;
    private ViewGroup decorView;//activity的根View
    private ViewGroup rootView;//黑色半透明背景View
    private OnDismissListener onDismissListener;//小时Listener
    private boolean isDismissing;
    private Animation outAnim;//退出动画
    private Animation inAnim;//进入动画
    private final int gravity = Gravity.BOTTOM;

    public BottomPopPanel(Context context, int layoutId) {
        this.context = context;
        //进行父View和子View的初始化工作
        initView(this.context);
        //把我们的自定义View放到contentContainer里面去
        ScaleScreenHelperFactory.getInstance().loadView((ViewGroup) LayoutInflater.from(context).inflate(layoutId, contentContainer));

    }

    private void initView(Context context) {
        this.context = context;
        LayoutInflater layoutInflater = LayoutInflater.from(this.context);
        //获取该一个Activity底层父View正规写法,R.id.content是每个布局文件都会包含的Id这里可以看Activity的底层实现原理
        //说句实话当初看,Activity inflatelayout的底层的时候是看见过这些代码的,但是当时看完之后感觉没有什么用处而且
        decorView = (ViewGroup) ((Activity) context).getWindow().getDecorView().findViewById(android.R.id.content);
        //由于Activity的底层父View的布局是FrameLayout所以我们这个RootView为了模拟popWindow可以直接设置成黑色半透明的背景
        //宽和高设置为占满就可以了 用的确实和巧妙啊
        rootView = (ViewGroup) ScaleScreenHelperFactory.getInstance().loadView((ViewGroup) layoutInflater.inflate(R.layout.view_base_pickerview, decorView, false));
        rootView.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        //过滤出我们加载自定义View 的父V
        contentContainer = (FrameLayout) rootView.findViewById(R.id.content_container);
        contentContainer.setLayoutParams(params);
        //初始化 进入和滑出动画
        inAnim = getInAnimation();
        outAnim = getOutAnimation();
    }

    /**
     * 添加这个View到Activity的根视图
     */
    public void show() {
        if (isShowing()) {
            return;
        }
        onAttached(rootView);
    }

    //通过onAttached 和 remove 实现显示Pop 和得到Pop的当前显示状态
    /**
     * show的时候调用
     *
     * @param view 这个View
     */
    private void onAttached(View view) {
        decorView.addView(view);
        contentContainer.startAnimation(inAnim);
    }

    /**
     * 检测该View是不是已经添加到根视图
     *
     * @return 如果视图已经存在该View返回true
     */
    public boolean isShowing() {
        View view = decorView.findViewById(R.id.outmost_container);
        return view != null;
    }

    public void dismiss() {
        if (isDismissing) {
            return;
        }
        //消失动画
        outAnim.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {

            }
            @Override
            public void onAnimationEnd(Animation animation) {
                decorView.post(new Runnable() {
                    @Override
                    public void run() {
                        //从activity根视图移除
                        decorView.removeView(rootView);
                        isDismissing = false;
                        //动画结束调用自定义dismiss函数
                        if (onDismissListener != null) {
                            onDismissListener.onDismiss(BottomPopPanel.this);
                        }
                    }
                });
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
        contentContainer.startAnimation(outAnim);
        //是否正在消失状态
        isDismissing = true;
    }

    //加载滑入动画
    public Animation getInAnimation() {
        return AnimationUtils.loadAnimation(context, R.anim.slide_in_bottom);
    }
    //加载滑出动画
    public Animation getOutAnimation() {
        return AnimationUtils.loadAnimation(context, R.anim.slide_out_bottom);
    }

    public BottomPopPanel setOnDismissListener(OnDismissListener onDismissListener) {
        this.onDismissListener = onDismissListener;
        //直接调用dismiss函数 dismiss函数包含了 显示接口的消失方法
        dismiss();
        return this;
    }

    public BottomPopPanel setCancelable(boolean isCancelable) {
        View view = rootView.findViewById(R.id.outmost_container);

        if (isCancelable) {
            view.setOnTouchListener(onCancelableTouchListener);
        } else {
            view.setOnTouchListener(null);
        }
        return this;
    }

    /**
     * Called when the user touch on black overlay in order to dismiss the dialog
     */
    private final View.OnTouchListener onCancelableTouchListener = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_UP) {
                dismiss();
            }
            return false;
        }
    };


    public interface OnDismissListener {
        void onDismiss(Object o);
    }

    public View findViewById(int id) {
        return contentContainer.findViewById(id);
    }

}

补充一些自定义动画

slide_in_anim

<?xml version="1.0" encoding="UTF-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate
        android:duration="@integer/animation_default_duration"
        android:fromXDelta="0%"
        android:fromYDelta="100%"
        android:toXDelta="0%"
        android:toYDelta="0%" />
</set>

slide_out_anim

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:shareInterpolator="false">

  <translate
      android:duration="@integer/animation_default_duration"
      android:fromXDelta="0%"
      android:toXDelta="0%"
      android:fromYDelta="0%"
      android:toYDelta="100%"/>
</set>

在Ativity或者Fragment中的使用

当我们设置点击按钮的时候将下面的代码放进去

 final BottomPopPanel bottomView = new BottomPopPanel(getActivity(), R.layout.view_bottom_chosecharge);
                   bottomView.findViewById(R.id.free).setOnClickListener(new View.OnClickListener() {
                       @Override
                       public void onClick(View view) {
                           bottomView.setOnDismissListener(new BottomPopPanel.OnDismissListener() {
                               @Override
                               public void onDismiss(Object o) {


                               }
                           });
                       }
                   });
                   bottomView.setCancelable(true);
                   bottomView.show();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好!对于 Android 自定义登录弹窗,您可以使用 Dialog 或者 PopupWindow 来实现。以下是一个简单的示例代码: 1. 创建一个自定义的布局文件,例如 login_dialog.xml,用于定义登录弹窗的样式和内容: ```xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <EditText android:id="@+id/etUsername" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="用户名"/> <EditText android:id="@+id/etPassword" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textPassword" android:hint="密码"/> <Button android:id="@+id/btnLogin" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="登录"/> </LinearLayout> ``` 2. 在您的 Activity 或者 Fragment 中,使用该自定义布局文件创建登录弹窗: ```java // 初始化弹窗 Dialog dialog = new Dialog(context); dialog.setContentView(R.layout.login_dialog); // 获取弹窗中的控件 EditText etUsername = dialog.findViewById(R.id.etUsername); EditText etPassword = dialog.findViewById(R.id.etPassword); Button btnLogin = dialog.findViewById(R.id.btnLogin); // 设置登录按钮的点击事件 btnLogin.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 在这里处理登录操作 String username = etUsername.getText().toString(); String password = etPassword.getText().toString(); // 执行登录逻辑... dialog.dismiss(); // 关闭弹窗 } }); // 显示弹窗 dialog.show(); ``` 3. 当用户点击登录按钮时,您可以在 OnClickListener 中处理登录逻辑。 希望这个简单的示例能够帮助到您!如果您有任何问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值