您的位置:首页 > 编程语言

封装弹性dialog框架,使用只需一行代码

2017-08-02 17:47 441 查看

效果图



效果图

使用

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: