内容简介:大家看到GIF,就知道,其自定义很是简单,为何还要说一说呢?主要是 github 上有很多大佬写的很好的库,只是功能多了,文件就多了,很多时候引入一个第三方,还得考虑方法数,库的大小等,而且有些时候,我们不需要那么多功能.
Github地址 ,欢迎点赞,fork
大家看到GIF,就知道,其自定义很是简单,为何还要说一说呢?
主要是 github 上有很多大佬写的很好的库,只是功能多了,文件就多了,很多时候引入一个第三方,还得考虑方法数,库的大小等,而且有些时候,我们不需要那么多功能.
工作中使用频率又很高,每使用一次自定义一个,确实有些浪费精力了.本文还是在大佬的肩膀上做了些拓展,具体大佬链接,文章末尾给出.
好了,下面进入正题(PS:源码有彩蛋哦).
只需要四个类 + 几个 XML 文件即可,即拷即用
接下来我们依次讲解:
- JAlertDialog
- JAlertController
- JDialogViewHelper
- OnJAlertDialogClickListener
- 其他几个 XML 文件
首先我们看看 JAlertDialog:
public class JAlertDialog extends Dialog { private JAlertController mAlert; public JAlertDialog(Context context, int themeResId) { super(context, themeResId); mAlert = new JAlertController(this, getWindow()); } public static class Builder { private final JAlertController.AlertParams mAlertParams; public Builder(Context context) { this(context, R.style.JDialogStyle); } public Builder(Context context, @StyleRes int themeRes) { mAlertParams = new JAlertController.AlertParams(context, themeRes); } public Builder setContentView(View view) { mAlertParams.mView = view; mAlertParams.mViewLayoutResId = 0; return this; } public Builder setContentView(int layoutResId) { mAlertParams.mView = null; mAlertParams.mViewLayoutResId = layoutResId; return this; } public Builder setCancelable(boolean cancelable) { mAlertParams.mCancelable = cancelable; return this; } public Builder setText(@IdRes int viewId, CharSequence text) { mAlertParams.mTextArr.put(viewId,text); return this; } public Builder setFromBottom() { mAlertParams.mGravity = Gravity.BOTTOM; return this; } public Builder setAnimation(@StyleRes int styleAnim) { mAlertParams.mAnimation = styleAnim; return this; } public Builder setHasAnimation(boolean hasAnimation) { mAlertParams.mHasAnimation = hasAnimation; return this; } public Builder setFullWidth() { mAlertParams.mWidth = ViewGroup.LayoutParams.MATCH_PARENT; return this; } public Builder setWidthAndHeight(int width,int height) { mAlertParams.mWidth = width; mAlertParams.mHeight = height; return this; } public Builder setOnClick(@IdRes int viewId) { mAlertParams.mClickArr.put(mAlertParams.mClickArr.size(),viewId); return this; } public Builder setOnJAlertDialogCLickListener(OnJAlertDialogClickListener onJAlertDialogClickListener) { mAlertParams.mOnJAlertDialogClickListener = onJAlertDialogClickListener; return this; } public Builder setOnCancelListener(OnCancelListener onCancelListener) { mAlertParams.mOnCancelListener = onCancelListener; return this; } public Builder setOnOnDismissListener(OnDismissListener onDismissListener) { mAlertParams.mOnDismissListener = onDismissListener; return this; } public Builder setOnKeyListener(OnKeyListener onKeyListener) { mAlertParams.mOnKeyListener = onKeyListener; return this; } public JAlertDialog create() { final JAlertDialog dialog = new JAlertDialog(mAlertParams.mContext, mAlertParams.mThemeRes); mAlertParams.apply(dialog.mAlert); dialog.setCancelable(mAlertParams.mCancelable); if (mAlertParams.mCancelable) { dialog.setCanceledOnTouchOutside(true); } dialog.setOnCancelListener(mAlertParams.mOnCancelListener); dialog.setOnDismissListener(mAlertParams.mOnDismissListener); if (mAlertParams.mOnKeyListener != null) { dialog.setOnKeyListener(mAlertParams.mOnKeyListener); } return dialog; } public JAlertDialog show() { JAlertDialog dialog = create(); dialog.show(); return dialog; } } } 复制代码
代码没有什么注释,其实很简单,就是一个建造者模式,仿系统做法,没有什么很特别的地方...
然后我们看看 JAlertController:
public class JAlertController { private JAlertDialog mDialog; private Window mWindow; public JAlertController(JAlertDialog dialog, Window window) { mDialog = dialog; mWindow = window; } public JAlertDialog getDialog() { return mDialog; } public Window getWindow() { return mWindow; } public static class AlertParams { public Context mContext; /** * Dialog 主题,有一个默认主题 */ public int mThemeRes; /** * 存放显示文本的控件和文本内容 */ public SparseArray<CharSequence> mTextArr = new SparseArray<>(); /** * 存放点击事件的控件和监听 */ public SparseIntArray mClickArr = new SparseIntArray(); /** * 点击空白是否可以取消,默认不可以 */ public boolean mCancelable = false; /** * Dialog 取消监听 */ public DialogInterface.OnCancelListener mOnCancelListener; /** * Dialog 消失监听 */ public DialogInterface.OnDismissListener mOnDismissListener; /** * Dialog 按键监听 */ public DialogInterface.OnKeyListener mOnKeyListener; /** * Dialog 布局 View */ public View mView; /** * Dialog 布局 ID */ public int mViewLayoutResId; public int mWidth = ViewGroup.LayoutParams.WRAP_CONTENT; public int mHeight = ViewGroup.LayoutParams.WRAP_CONTENT; public int mGravity = Gravity.CENTER; public int mAnimation = R.style.JDialogAnimation; public boolean mHasAnimation = true; public OnJAlertDialogClickListener mOnJAlertDialogClickListener; public AlertParams(Context context, @StyleRes int themeRes) { mContext = context; mThemeRes = themeRes; } /** * 设置参数 */ public void apply(JAlertController alert) { JDialogViewHelper viewHelper = null; // 1. 设置布局 if (0 != mViewLayoutResId) { viewHelper = new JDialogViewHelper(mContext, mViewLayoutResId); } if (null != mView) { viewHelper = new JDialogViewHelper(mContext, mView); } if (null == viewHelper) { throw new IllegalArgumentException("请设置Dialog布局"); } alert.getDialog().setContentView(viewHelper.getContentView()); viewHelper.setOnJAlertDialogClickListener(mOnJAlertDialogClickListener); // 2. 设置文本,控件和文本内容一一对应的 for (int i = 0, len = mTextArr.size(); i < len; i++) { viewHelper.setText(mTextArr.keyAt(i), mTextArr.valueAt(i)); } // 3. 设置点击事件 for (int i = 0, len = mClickArr.size(); i < len; i++) { viewHelper.setOnClick(mClickArr.keyAt(i), mClickArr.valueAt(i)); } // 4. 设置dialog宽高动画等 Window window = alert.getWindow(); window.setGravity(mGravity); if (mHasAnimation) { window.setWindowAnimations(mAnimation); } WindowManager.LayoutParams params = window.getAttributes(); params.width = mWidth; params.height = mHeight; window.setAttributes(params); alert.getDialog().setOnCancelListener(mOnCancelListener); alert.getDialog().setOnDismissListener(mOnDismissListener); } } } 复制代码
这里,有意思点的是, 注释3 ,点击事件,我通过拓展类似文本设置效果,在点击事件上做了点优化,具体看使用代码,不要心急!
接着,瞅瞅那个布局文件:JDialogViewHelper
public class JDialogViewHelper { private Context mContext; private View mContentView; private SparseArray<WeakReference<View>> mViews; public OnJAlertDialogClickListener mOnJAlertDialogClickListener; public JDialogViewHelper(Context context, int viewLayoutResId) { mViews = new SparseArray<>(); mContentView = LayoutInflater.from(context).inflate(viewLayoutResId, null); } public JDialogViewHelper(Context context, View view) { mViews = new SparseArray<>(); mContentView = view; } public void setText(@IdRes int viewId, CharSequence charSequence) { TextView textView = getView(viewId); if (null != textView) { textView.setText(charSequence); } } public void setOnClick(final int position, @IdRes int viewId) { View view = getView(viewId); if (null != view) { view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (null != mOnJAlertDialogClickListener){ mOnJAlertDialogClickListener.onClick(v,position); } } }); } } public View getContentView() { return mContentView; } @SuppressWarnings("unchecked") public <T extends View> T getView(int viewId) { View view = null; WeakReference<View> viewWeakReference = mViews.get(viewId); if (null != viewWeakReference) { view = viewWeakReference.get(); } if (null == view) { view = mContentView.findViewById(viewId); if (null != view) mViews.put(viewId, new WeakReference<View>(view)); } return (T) view; } 复制代码
借鉴了类似 ListView 中 自定义的 ViewHolder ,不说什么了,一目了然啊,哈哈
倒数第二就是看哈回调了,贴个代码,来凑行数....,哈哈
public void setOnJAlertDialogClickListener(OnJAlertDialogClickListener onJAlertDialogClickListener) { mOnJAlertDialogClickListener = onJAlertDialogClickListener; } } 复制代码
一个简单的回调,我能说什么呢...
最后就是几个我就一股脑都抛出来了,准备接招!!!
1.在 res/anim 中创建自己需要的动画,我这里贴上gif效果的动画
jdialog_enter.xml ---> 这个必须要,默认效果,当然如果你拷贝源码修改了也是可以不要的...
<?xml version="1.0" encoding="utf-8"?> <translate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="200" android:fromYDelta="100%" android:toYDelta="0" /> 复制代码
jdialog_exit.xml ---> 这个必须要,默认效果,当然如果你拷贝源码修改了也是可以不要的...
<?xml version="1.0" encoding="utf-8"?> <translate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="200" android:fromYDelta="0" android:toYDelta="100%" /> 复制代码
update_scale_fade_in.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <scale android:fromXScale="0.0" android:fromYScale="0.0" android:toXScale="1.0" android:toYScale="1.0" android:duration="400" android:pivotX="50%" android:pivotY="50%" /> <alpha android:duration="400" android:fromAlpha="0.0" android:toAlpha="1.0" > </alpha> </set> 复制代码
update_scale_fade_out.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <scale android:fromXScale="1.0" android:fromYScale="1.0" android:toXScale="0.0" android:toYScale="0.0" android:duration="400" android:pivotX="50%" android:pivotY="50%" /> <alpha android:duration="400" android:fromAlpha="1.0" android:toAlpha="0.0" > </alpha> </set> 复制代码
-
在 res/values/style.xml 设置 Dialog 属性 和动画
<!-- 默认使用,所以必须拷贝此 style ,这个必须要,默认效果,当然如果你拷贝源码修改了也是可以不要的... --> <style name="JDialogStyle" 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:backgroundDimAmount">0.3</item> <!-- 无标题 --> <item name="android:windowNoTitle">true</item> <!-- 半透明 --> <item name="android:windowIsTranslucent">true</item> <!-- Dialog进入及退出动画,这样所有使用此 style 都有这个动画, 可以单独指定的 --> <!--<item name="android:windowAnimationStyle">@style/JDialogAnimation</item>--> </style> <!-- 默认使用,所以必须拷贝此 style ,这个必须要,默认效果,当然如果你拷贝源码修改了也是可以不要的...--> <!-- 自定义动画,可以使用系统的,即把parent= 后面的直接 "android:windowAnimationStyle"> --> <style name="JDialogAnimation" parent="@android:style/Animation.Dialog"> <item name="android:windowEnterAnimation">@anim/jdialog_enter</item> <item name="android:windowExitAnimation">@anim/jdialog_exit</item> </style> <!-- 升级时使用的类似效果 --> <style name="UpdateAnimation" parent="@android:style/Animation.Dialog"> <item name="android:windowEnterAnimation">@anim/update_scale_fade_in</item> <item name="android:windowExitAnimation">@anim/update_scale_fade_out</item> </style> 复制代码
基本上就是这么多了,是不是很简单呢?
下面看看基本用法
class MainActivity : AppCompatActivity() { private lateinit var mBottomDialog: JAlertDialog; private lateinit var mUpdateDialog: JAlertDialog; override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) initBottomDialog() initUpdateDialog() tv_center.setOnClickListener { mBottomDialog.show() } tv_updpate.setOnClickListener { mUpdateDialog.show() } } /** * 底部弹出 */ private fun initBottomDialog() { mBottomDialog = JAlertDialog.Builder(this) .setContentView(R.layout.dialog) // 设置布局,可以是 View .setCancelable(false) .setHasAnimation(true) //是否拥有动画,默认true, // .setAnimation() // 设置动画,会覆盖默认动画 .setText(R.id.btn_left, "test1") // 设置空间文本,如果有多个,则调用多次即可 .setFromBottom() // 是否是从底部弹出,具体效果可以自己试试,感受更明显 .setFullWidth() // 宽度铺满屏幕 // .setWidthAndHeight() // 可以指定宽高(如果升级APP提示弹框等...) .setOnClick(R.id.btn_left) //第一个点击的 View .setOnClick(R.id.btn_right) // 第二个点击的 View // 如果设置了点击 View,则需要下面这个方法回调, 注意 position 是从 0 开始的 .setOnJAlertDialogCLickListener(OnJAlertDialogClickListener { view, position -> if (mBottomDialog.isShowing) { mBottomDialog.dismiss() } when (position) { // 这个顺序,和上面添加点击 View 是一致的 0 -> Toast.makeText(this@MainActivity, "点击左边按钮", Toast.LENGTH_SHORT).show() 1 -> Toast.makeText(this@MainActivity, "点击右边按钮", Toast.LENGTH_SHORT).show() } }).create() } /** * 中间弹出,类似升级APP提示框 */ private fun initUpdateDialog() { val view = LayoutInflater.from(this).inflate(R.layout.dialog_update_app, null); // 彩蛋一枚,自定义 ArcBackgroundDrawable 解决底部 TextViev 设置背景没有圆角问题 // 当然直接写xml也可以,只是本例中多了一个圆弧效果,看起来更 cool, 哈哈,不喜欢,你来打我啊!@! val tv_bottom_update = view.findViewById<TextView>(R.id.tv_bottom_update); tv_bottom_update.background = ArcBackgroundDrawable() mUpdateDialog = JAlertDialog.Builder(this) .setAnimation(R.style.UpdateAnimation) .setCancelable(false) .setContentView(view) .setOnClick(R.id.iv_close_update) .setOnClick(R.id.tv_bottom_update) .setOnJAlertDialogCLickListener { view, position -> when (position) { 0 -> { // 关闭 mUpdateDialog.dismiss() } 1 -> { // 开始下载 mUpdateDialog.dismiss() // TODO } } } .create() } } 复制代码
用法需要注意的地方,我有提示哈,其实就是自定义一个布局,然后把需要设置文本和点击的,给设置了,最后时从哪里弹起给搞设置下.基本就可以了!我没有过多的提供动画效果,需要什么样的自己发挥了! 这样在使用时还是比较方便的,我们多个项目使用哦!
哈哈,彩蛋就是源码有一个自定义的圆弧 ArcBackgroundDrawable, 大家可以去看看哈,就是升级弹窗底部的那个圆弧,可以解决比如一个圆形背景,但是底部按钮给了背景后圆弧不见了的问题!
膜拜的大神:
- https://www.jianshu.com/p/87288925ee1f
以上所述就是小编给大家介绍的《Android 最简单的自定义Dialog之一》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Android 自定义 View (04自定义属性)
- Vue自定义组件(简单实现一个自定义组件)
- Android 自定义View:深入理解自定义属性(七)
- Qt编写自定义控件20-自定义饼图 原 荐
- SpringBoot2 | SpringBoot自定义AutoConfiguration | SpringBoot自定义starter(五)
- 『互联网架构』软件架构-springboot自定义视图和自定义Starter(90)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
计算机组成与设计硬件/软件接口
[美] David A.Patterson、John L.Hennessy / 郑纬民 / 机械工业出版社 / 2007-4 / 75.00元
《计算机组成与设计硬件:软件接口》(原书第3版)是计算机组成的经典教材。全书着眼于当前计算机设计中最基本的概念,展示了软硬件间的关系,并全面介绍当代计算机系统发展的主流技术和最新成就。同以往版本一样,《计算机组成与设计硬件:软件接口》(原书第3版)采用MIPS处理器作为展示计算机硬件技术基本功能的核心。书中逐条指令地列举了完整的MIPS指令集,并介绍了网络和多处理器结构的基本内容。将CPU性能和程......一起来看看 《计算机组成与设计硬件/软件接口》 这本书的介绍吧!