一个简单的自定义DialogFragment

1、 概述
DialogFragment在android 3.0时被引入。是一种特殊的Fragment,用于在Activity的内容之上展示一个模态的对话框。典型的用于:展示警告框,输入框,确认框等等。在DialogFragment产生之前,我们创建对话框:一般采用AlertDialog和Dialog。注:官方不推荐直接使用Dialog创建对话框。

2、 好处与用法

使用DialogFragment来管理对话框,当旋转屏幕和按下后退键时可以更好的管理其声明周期,它和Fragment有着基本一致的声明周期。且DialogFragment也允许开发者把Dialog作为内嵌的组件进行重用,类似Fragment(可以在大屏幕和小屏幕显示出不同的效果)。

以上引用:http://blog.csdn.net/lmj623565791/article/details/37815413

闲话少说直接先上效果图,以防那么没耐心同学直接跑掉


非常简单中间就一个动画。

自定义的loadingView 效果如下

public class LoadingView extends View implements ValueAnimator.AnimatorUpdateListener {
    private Context context;
    private Paint paint;
    private PathMeasure pathMeasure;
    private Path showPath;
    private int mHeight;
    private int mWith;
    private ValueAnimator valueAnimator;
    private float dtPath;
    private float startPoint;
    private int radius = 80;

    public LoadingView(Context context) {
        super(context);
        init(context);
    }


    public LoadingView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public LoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }


    private void init(Context context) {
        this.context = context;
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setColor(Color.RED);
        paint.setStrokeWidth(Displayutil.dip2px(getContext(), 3));
        paint.setStyle(Paint.Style.STROKE);
        Path path = new Path();
        path.addCircle(0, 0, radius, Path.Direction.CW);
        pathMeasure = new PathMeasure(path, false);
        valueAnimator = ValueAnimator.ofFloat(0, ((float) (2 * radius * Math.PI) / 4));
        valueAnimator.setDuration(2000).setRepeatCount(Animation.INFINITE);
        valueAnimator.addUpdateListener(this);
        valueAnimator.start();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
        // 在wrap_content的情况下默认长度为200dp
        int minSize = Displayutil.dip2px(context, radius);
        // wrap_content的specMode是AT_MOST模式,这种情况下宽/高等同于specSize
        // 查表得这种情况下specSize等同于parentSize,也就是父容器当前剩余的大小
        // 在wrap_content的情况下如果特殊处理,效果等同martch_parent
        if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(minSize, minSize);
        } else if (widthSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(minSize, heightSpecSize);
        } else if (heightSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(widthSpecSize, minSize);
        }


    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mHeight = getMeasuredHeight();
        mWith = getMeasuredWidth();
        canvas.translate(mWith / 2, getHeight() / 2);
        Path path = new Path();
        pathMeasure.getSegment(startPoint, startPoint , path, true);
        if (startPoint + dtPath < 2 * radius * Math.PI) {
            pathMeasure.getSegment(startPoint, startPoint + dtPath, path, true);
        } else {
            pathMeasure.getSegment(startPoint, (float) (2 * radius * Math.PI), path, true);
        }

        canvas.drawPath(path, paint);
    }


    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        dtPath = (float) animation.getAnimatedValue();
        startPoint = dtPath * ((float) (2 * radius * Math.PI)) / ((float) (2 * radius * Math.PI) / 4);
        if(startPoint!=0){
            postInvalidateDelayed(300);

        }
    }


    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        valueAnimator.end();
    }
}
下面一步步说咯

1继承view 处理onMeasure,

这里不多说,下面这些代码,就是为了让warp_content 写法固定,注释写的很详细了,不理解的建议,看viewmeasure过程源码,不细说,如果需要,后面我会写一篇博客继续说。

int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
        // 在wrap_content的情况下默认长度为200dp
        int minSize = Displayutil.dip2px(context, radius);
        // wrap_content的specMode是AT_MOST模式,这种情况下宽/高等同于specSize
        // 查表得这种情况下specSize等同于parentSize,也就是父容器当前剩余的大小
        // 在wrap_content的情况下如果特殊处理,效果等同martch_parent
        if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(minSize, minSize);
        } else if (widthSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(minSize, heightSpecSize);
        } else if (heightSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(widthSpecSize, minSize);
        }

2 看init方法

private void init(Context context) {
    this.context = context;
    paint = new Paint();
    paint.setAntiAlias(true);
    paint.setColor(Color.RED);
    paint.setStrokeWidth(Displayutil.dip2px(getContext(), 3));
    paint.setStyle(Paint.Style.STROKE);
    Path path = new Path();
    path.addCircle(0, 0, radius, Path.Direction.CW);
    pathMeasure = new PathMeasure(path, false);
    valueAnimator = ValueAnimator.ofFloat(0, ((float) (2 * radius * Math.PI) / 4));
    valueAnimator.setDuration(2000).setRepeatCount(Animation.INFINITE);
    valueAnimator.addUpdateListener(this);
    valueAnimator.start();
}
init 做了3件事情:

1 初始化了画笔

2规划好了,我们要取的path 路径,就是一个环圈,我们后面取的路径都是从这个圆圈中取的。

    Path path = new Path();
    path.addCircle(0, 0, radius, Path.Direction.CW);

3 初始话了一个属性动画,设置了监听。

监听内的方法。

@Override
public void onAnimationUpdate(ValueAnimator animation) {
    dtPath = (float) animation.getAnimatedValue();
    startPoint = dtPath * ((float) (2 * radius * Math.PI)) / ((float) (2 * radius * Math.PI) / 4);
    if(startPoint!=0){
        postInvalidateDelayed(300);

    }
}
dapath 就是我们需要绘制圆弧的长度,通过看valueanimatior 知道最小是0,最大是圆的周长的1/4.

startPoint 开始绘制圆弧的位置,原理很简单,根据dapth 实际值于最大值的比例,确定开始绘制的位置,保证在dapth 长度变化一个周期内,开始绘制位置沿着圆周移动一圈。

然后invalidateDekayed 引起view从新绘制,

处理ondraw()

这里就是动画的重点了,这里实现方式配合了valueAnimator ,你也可以自定义插值起根估值器来实现,那样稍微复杂,这里直接使用了动画,但是自定义控件时候,使用动画,小心内存泄漏问题。后面我们会说。下面一行一行的说。

mHeight = getMeasuredHeight();
        mWith = getMeasuredWidth();     获取到空间的宽高,注意不要直接使用getheight()  getWidth(), 可能会得不到宽高,这也是view 测试基础了,不多说。
        canvas.translate(mWith / 2, getHeight() / 2);
        Path path = new Path()
;
     

    pathMeasure.getSegment(startPoint, startPoint + dtPath, path, true);

这是最关键的一个方法了,4个参数分别代表,开始截取path的起点,path截取终点,path 用来保存我们要截取的对象,最后一个参数表示截取的路径是狗需要首位相连。
        if (startPoint + dtPath < 2 * radius * Math.PI) {
            pathMeasure.getSegment(startPoint, startPoint + dtPath, path, true);
        } else {
            pathMeasure.getSegment(startPoint, (float) (2 * radius * Math.PI), path, true);
        }

绘制
        canvas.drawPath(path, paint);

@Override
protected void onDetachedFromWindow() {
    super.onDetachedFromWindow();
    valueAnimator.end();
}
解决使用动画可能引起的内存泄漏问题。当view离开window 时候将动画关闭。

dialogFragment 简单许多了

public class LoadingDialog extends DialogFragment{

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
        getDialog().setCanceledOnTouchOutside(false);
        getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        return inflater.inflate(R.layout.loding_dialog,null);
    }
}
去掉了标题,使用style 将背景变为透明的,设置了dialog 的布局,

注意使用dailogfragment 时候oncreateview 与onCreateDIalog方法只能实现一个,否则的话会报错,上面鸿洋大神博客说的很清楚是或者关系。

好了这样一个简单的dialogfragment 就完成了。

你可能感兴趣的:(工作总结)