封装弹性dialog框架,使用只需一行代码
2017-08-02 17:47
441 查看
效果图
![](http://upload-images.jianshu.io/upload_images/5442739-a69e9b9374983727.gif?imageMogr2/auto-orient/strip)
效果图
使用
build.gradle中添加compile 'com.cool:elasticdialog:1.0.0'
你要使用的地方
if(elasticDialog== null) { elasticDialog = new ElasticDialog(this) .layout(R.layout.dialog_elastic) .arcColor(Color.WHITE) .duration(1000) .arcHight(40); mRecyclerView = elasticDialog.findViewById(R.id.recyclerview); }
布局文件dialog_elastic
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:id="@+id/recyclerview" android:layout_width="match_parent" android:layout_height="300dp" android:layout_gravity="bottom"> </android.support.v7.widget.RecyclerView> </FrameLayout>
有两点需要
注意:
布局文件dialog_elastic子View需要设置
android:layout_gravity="bottom"属性
根布局使用
FrameLayout
实现思路:
我们可以在dialog中设置的布局中做手脚,dialog的根布局使用FrameLayout,在渲染dialog的布局完成后,偷偷的添加一个背景view,放在FrameLayout的最底部,然后通过背景view的onDraw方法画view的背景,可以看到,背景view的背景是不规则的,首先想到的就是path,具体实现方式当然是贝塞尔曲线了,下面是具体步骤。
一、创建ElasticDialog
ElasticDialog是继承Dialog的1.1在构造函数里进行相关初始化
public ElasticDialog(@NonNull Context context) { super(context, R.style.stlyle_dialog_transparent_bg); this.mContext = context; mArcHight = dp2px(40);//弧形的高度 mDuration = 1000;//动画时长 arcColor = Color.WHITE;//弧形颜色 }
1.2设置dialog的布局和相关参数
/** * 设置dialog的布局 * @param layoutId * @return */ public ElasticDialog layout(int layoutId) { view = LayoutInflater.from(mContext).inflate(layoutId, null); setContentView(view); Window window = getWindow(); window.setGravity(Gravity.BOTTOM); window.setWindowAnimations(R.style.style_anim_bottom_in); WindowManager.LayoutParams params = window.getAttributes(); params.width = getContext().getResources().getDisplayMetrics().widthPixels; window.setAttributes(params); return this; }
其中看到的R.style.stlyle_dialog_transparent_bg和R.style.style_anim_bottom_in是两个主题,如下:
<!--透明背景dialog主题--> <style name="stlyle_dialog_transparent_bg" parent="android:style/Theme.Dialog"> <item name="android:windowFrame">@null</item> <item name="android:windowNoTitle">true</item> <item name="android:windowIsFloating">true</item> <item name="android:windowContentOverlay">@null</item> <item name="android:windowBackground">@android:color/transparent</item> </style> <!--底部弹框dialog动画主题--> <style name="style_anim_bottom_in"> <item name="android:windowEnterAnimation">@anim/dialog_enter</item> <item name="android:windowExitAnimation">@anim/dialog_exit</item> </style>
1.3显示dialog
@Override public void show() { super.show(); addBackgroundView();//添加背景view doAnim();//开始动画 } /** * 添加背景动画view */ private void addBackgroundView() { if (view instanceof FrameLayout) { FrameLayout fl = (FrameLayout) view; View backView = fl.getChildAt(0); if(backView instanceof ElasticBackgroundView){//判断之前是否已经添加过背景view return; } fl.measure(0, 0);//为了拿到根布局测量高度 int measuredHeight = fl.getMeasuredHeight(); int realHight = measuredHeight + mArcHight;//根布局高度加上圆弧高度 FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, realHight); backgroundView = new ElasticBackgroundView(mContext); backgroundView.setArcHight(mArcHight); backgroundView.setDuration(mDuration); backgroundView.setArcColor(arcColor); fl.addView(backgroundView, 0, layoutParams); }else { throw new IllegalArgumentException("dialog的根布局必须为FrameLayout"); } } /** * 开始动画 */ private void doAnim() { if (backgroundView != null) { backgroundView.doStartAnimation(); } }
二、绘制ElasticBackgroundView的背景
2.1初始化paint、path、动画时长
private void init() { mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setColor(Color.WHITE); mPaint.setStyle(Paint.Style.FILL); path = new Path(); mDuration = 1000; }
2.2重写onDraw方法
mArcHight为圆弧的高度,currentArcHight为动画过程中圆弧的高度,mWidth,mHight是背景View的宽高@Override protected void onDraw(Canvas canvas) { path.reset(); path.moveTo(0, mArcHight); path.quadTo(mWidth/2,currentArcHight,mWidth, mArcHight); path.lineTo(mWidth,mHight); path.lineTo(0,mHight); path.close(); canvas.drawPath(path,mPaint); }
2.3开启动画
public void doStartAnimation() { ValueAnimator valueAnimator = ValueAnimator.ofFloat(mArcHight,-mArcHight, mArcHight); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { currentArcHight = (float) valueAnimator.getAnimatedValue(); invalidate(); } }); valueAnimator.setDuration(mDuration); valueAnimator.start(); }
完整的ElasticDialog
public class ElasticDialog extends Dialog {
private ElasticBackgroundView backgroundView;
private Context mContext;
private View view;
private int mArcHight;//顶部遗留高度,默认40dp,白色圆弧形能够达到的高度相关连,经测试40效果较好
private long mDuration;//动画执行时间
private int arcColor;
public ElasticDialog(@NonNull Context context) {
super(context, R.style.stlyle_dialog_transparent_bg);
this.mContext = context;
mArcHight = dp2px(40);
mDuration = 1000;
arcColor = Color.WHITE;
}
/** * 设置dialog的布局 * @param layoutId * @return */ public ElasticDialog layout(int layoutId) { view = LayoutInflater.from(mContext).inflate(layoutId, null); setContentView(view); Window window = getWindow(); window.setGravity(Gravity.BOTTOM); window.setWindowAnimations(R.style.style_anim_bottom_in); WindowManager.LayoutParams params = window.getAttributes(); params.width = getContext().getResources().getDisplayMetrics().widthPixels; window.setAttributes(params); return this; }
@Override
public void show() {
super.show();
addBackgroundView();
doAnim();
}
/**
* 添加背景动画view
*/
private void addBackgroundView() {
if (view instanceof FrameLayout) {
FrameLayout fl = (FrameLayout) view;
View backView = fl.getChildAt(0);
if(backView instanceof ElasticBackgroundView){
return;
}
fl.measure(0, 0);
int measuredHeight = fl.getMeasuredHeight();
int realHight = measuredHeight + mArcHight;
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, realHight);
backgroundView = new ElasticBackgroundView(mContext);
backgroundView.setArcHight(mArcHight);
backgroundView.setDuration(mDuration);
backgroundView.setArcColor(arcColor);
fl.addView(backgroundView, 0, layoutParams);
}else {
throw new IllegalArgumentException("dialog的根布局必须为FrameLayout");
}
}
/**
* 开始动画
*/
private void doAnim() {
if (backgroundView != null) {
backgroundView.doStartAnimation();
}
}
/**
* 设置达到的弧高
* @param arcHight
* @return
*/
public ElasticDialog arcHight(int arcHight) {
this.mArcHight = dp2px(arcHight);
return this;
}
/**
* 设置背景动画时间
* @param duration
* @return
*/
public ElasticDialog duration(long duration) {
if (duration < 0) {
this.mDuration = 1000;
}
this.mDuration = duration;
return this;
}
/**
* 弧形背景颜色
* @param color
* @return
*/
public ElasticDialog arcColor(int color){
this.arcColor = color;
return this;
}
/**
* 是否可取消
* @param cancelable
* @return
*/
public ElasticDialog cancelable(boolean cancelable){
setCancelable(cancelable);
return this;
}
private int dp2px(int dp){
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, mContext.getResources().getDisplayMetrics());
}
}
完整的ElasticBackgroundView
public class ElasticBackgroundView extends View {
private Paint mPaint;
private Path path;
private int mWidth;
private int mHight;
private int mArcHight;//顶部遗留高度,默认40dp,遗留为了画顶部白色弧形并且能够看到
private float currentArcHight;
private long mDuration;//动画执行时间
public ElasticBackgroundView(Context context) {
this(context,null);
}
public ElasticBackgroundView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public ElasticBackgroundView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() { mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setColor(Color.WHITE); mPaint.setStyle(Paint.Style.FILL); path = new Path(); mDuration = 1000; }
@Override
protected void onDraw(Canvas canvas) {
path.reset();
path.moveTo(0, mArcHight);
path.quadTo(mWidth/2, currentArcHight,mWidth, mArcHight);
path.lineTo(mWidth,mHight);
path.lineTo(0,mHight);
path.close();
canvas.drawPath(path,mPaint);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = w;
mHight = h;
}
public void doStartAnimation() { ValueAnimator valueAnimator = ValueAnimator.ofFloat(mArcHight,-mArcHight, mArcHight); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { currentArcHight = (float) valueAnimator.getAnimatedValue(); invalidate(); } }); valueAnimator.setDuration(mDuration); valueAnimator.start(); }
public void setArcHight(int leaveHight){
this.mArcHight = leaveHight;
}
public void setDuration(long duration){
this.mDuration = duration;
}
public void setArcColor(int color){
if(mPaint != null){
mPaint.setColor(color);
}
}
}
源码地址:https://github.com/lkkz/ElasticDialog
欢迎star,issuse,fork
相关文章推荐
- viewpager 轮播框架---只需一行代码
- 自定义dialog,一行代码极简封装
- 只需一行代码实现增删查改,微软已经让我们很简单。谈AccessDataSource的使用。
- 对主流框架OKHttp的封装,达到一行代码实现一个业务逻辑
- 实现一个列表只需一行代码-RecyclerView适配器暴力封装
- 只需一行代码实现增删查改,微软已经让我们很简单。谈AccessDataSource的使用。
- JTable 的TableModel (使用TMF框架只用一行代码)
- 一个封装好的dialog工具类,减少重复的代码,简洁又方便使用!
- 使用VB将ASP代码封装生成DLL文件
- 只需一行代码就能让IE 6崩溃http://www.cnblogs.com/meil/archive/2007/08/07/846758.html
- 使用VB将ASP代码封装生成DLL文件
- 使用ASUnit单元测试框架测试ActionScript代码
- 在真实项目中使用第三方或开源代的代码,组件,中间件,框架的基本规则
- 在ASP.Net MVC框架下使用富文本编辑器(FCKEditor,更新至:v1.0.1)(2010-05-22:已加上源代码)
- 使用字节码处理框架javassist动态注入代码
- java,jsp生成UUID 超简单,只需一行代码
- 只需写一行代码就可杜绝iframe挂马
- 只需一行代码就能让IE 6崩溃
- 只需一行代码就能让IE6崩溃
- 使用Abator生成iBatis代码框架