ITPub博客

首页 > IT职业 > IT生活 > 淘宝首页动画的实现

淘宝首页动画的实现

IT生活 作者:nopower 时间:2021-09-09 09:54:10 0 删除 编辑

今天来写一个淘宝的一个小动画,一看觉得挺简单的,但是实际操作起来,感觉有点麻烦,遇到的问题也比较多,不过好在模仿出来了,好了给大家看看效果。 
这是老版本的,模拟器上面的和现版本的不一致 
这个是新版本的,下面的布局Bi老版本要稍微复杂一点。

接下来看看主界面的布局结构,最外面的是一个ViewGroup,然后就是一个“+”的View,再就是文本。 
下面我们就来完成这个View的书写,先定义一个ViewGroup,在定义一个View画上“+”,然后ViewGroup里面加上该View和文本内容。

 @Override
    protected void onDraw(Canvas canvas) {        super.onDraw(canvas); //画矩形的背景       canvas.drawRect(0,getMeasuredWidth()/2,getMeasuredWidth(),getMeasuredHeight(),mPaint);
        RectF rectF = new RectF(0,0,getMeasuredWidth(),getMeasuredHeight()/2); //画圆       canvas.drawCircle(getMeasuredWidth()/2,getMeasuredWidth()/2,getMeasuredWidth()/2,mPaint);
    }//测量的话,因为我们这是特定的布局,所以就没考虑到硬编码的问题,因为该容器不具备通用性
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        //测量子View,这里巨鼎父容器大小的是底部的TextView,所以就一该View为基准,设置父布局,其中TextView的上下左右的Margin都是可以控制的
        measureChildren(widthMeasureSpec,heightMeasureSpec);        int w = getChildAt(0).getMeasuredWidth();        int h = getChildAt(0).getMeasuredHeight();
        imgRadius = w/2;
        myLitterXView.init();        int width = w + marginLeftOrRightText * 2;        int height =  h + marginBottomText + marginTopText + imgRadius + width/2;        //最后将理想的宽高赋值上去。
        setMeasuredDimension(width,height);
    }    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {    //layout就是确定子View的位置的,这个就是个算数问题,没啥好说的
        View view = getChildAt(0);
        view.layout(
                marginLeftOrRightText,
                getMeasuredHeight()-view.getMeasuredHeight()-marginBottomText,
                marginLeftOrRightText+view.getMeasuredWidth(),
                getMeasuredHeight()-marginBottomText
                );
        View v = getChildAt(1);
        v.layout(
                marginLeftOrRightText,imgMarginTop,getMeasuredWidth()-marginLeftOrRightText,imgMarginTop+imgRadius*2
        );
    }

由于ViewGrou只是负责装载子View,并不承担绘制工作,但是我们这里需要其承担一定的绘制工作,那么就必须 setWillNotDraw(false);,让其调用draw()方法.

 private void init() {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setColor(color);
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);        //强制让容器执行绘制工作
        setWillNotDraw(false);
        textView = new TextView(getContext());
        textView.setText("发布");
        textView.setTextColor(Color.WHITE);
        LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        textView.setLayoutParams(lp);
        addView(textView);
        myLitterXView = new MyLitterXView(getContext());
        myLitterXView.setLayoutParams(lp);
        addView(myLitterXView);
        setOnClickListener(new OnClickListener() {            @Override
            public void onClick(View v) {                if (mClickListener!=null)mClickListener.click(v);
                myLitterXView.change(myLitterXView.model==TO_SPECIAL?TO_NOMAL:TO_SPECIAL);
            }
        });
    }

以上还只是完成了最基本的步骤,“+”View的定义

@Override 
protected void onDraw(Canvas canvas) { 
super.onDraw(canvas); 
canvas.drawColor(0x00000000); 
//画两条线,比较简单 canvas.drawLine(hLine[0].getX(),hLine[0].getY(),hLine[1].getX(),hLine[1].getY(),paint); 
canvas.drawLine(vLine[0].getX(),vLine[0].getY(),vLine[1].getX(),vLine[1].getY(),paint); 
canvas.restore(); 
}

说一下旋转动画的这几个参数,旋转的起始角度,最终角度,x轴的参照位置,参照点,y轴的参照位置,y轴参照点 
RotateAnimation(float fromDegrees, float toDegrees, int pivotXType, float pivotXValue, 
int pivotYType, float pivotYValue)

animation2 = new RotateAnimation(45,0,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);

通过普通的补间动画完成该旋转功能即可。如此下来,就差不多一级界面差不多了,接下来分析点击动画的组成部分。

点击一下,会有一个全屏的Window,这是必须的,别的方法也可以但是,没有该效果好,在window上面操作动画,这里要特别注意,当我们点击了一级界面的按钮后,Window添加布局,然而该View何时测量完毕?什么时候去开启第一次的动画?这都值得我们思考 
如果对Window不太了解的可以看看我的第一篇博客

public class MyWindow {    private WindowManager mWindowManager;    private WindowManager.LayoutParams mLp;    private Activity context;    private View view;    //WindowManger需要基本的一些配置
    public MyWindow(Activity context) {        this.context = context;
        mWindowManager = context.getWindowManager();
        mLp = new WindowManager.LayoutParams();
        mLp.height = WindowManager.LayoutParams.MATCH_PARENT;        //这是表示Window的左上角的位置
        mLp.x = 0;
        mLp.y = 0;
        mLp.width = WindowManager.LayoutParams.MATCH_PARENT;
        mLp.flags = WindowManager.LayoutParams.FLAG_DITHER;
        mLp.format = PixelFormat.TRANSLUCENT;
    }    public void addView(View view){        this.view = view;
        mWindowManager.addView(view,mLp);
    }    public void removeView(){        if (mWindowManager==null)return;
        mWindowManager.removeView(view);
        context = null;
    }
}

Window有了,下面我们要定义动画View了。在此之前我们要将动画View设置在一级菜单的上方,那么我们就要得到一级菜单的高度或者是在屏幕当中的位置(可以使用getLocationOnWindow,参数是个长度为2的整型数组,分别为x,y的坐标)。

圆形的TextView通过canvas.drawCircle(radius, radius, radius, mPaint); 这里直接在调用父方法前绘制背景图层。

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myMenuView = (MyMenuView) findViewById(R.id.menu_view);
        final List list = new ArrayList();
        list.add("发布");
        list.add("报价");
        contentView = (RelativeLayout) LayoutInflater.from(this).inflate(R.layout.animator_view, null);
        myAnimatorView = (com.yzz.android.animator.MyAnimatorView) contentView.getChildAt(0);
        myAnimatorView.init(Color.rgb(12, 22, 44), Color.WHITE, list);
        myWindow = new MyWindow(this);
        myAnimatorView.setWindow(myWindow);
        myAnimatorView.setRadius(50);
        int count = myAnimatorView.getChildCount();
        for (int i = 0; i 
 @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {    //这里会layout两次,第一次是没有设置高度时的layout,第二次是动态设置height是触发的layout
        if (radius 

这里使用的属性动画,属性动画的有点就是在动画的过程中改变了View的位置属性,这样点击区域就会随之View的移动而改变。通过PropertyValuesHolder来操作一组动画,很方便,当然也可以时候AnimatorSet来实现,都可以。注意:动画的位置规则是相对的,相对于当前状态,平移的话,x>0,y>0表示这x右移,y下移。

 public void initAnimation() {
        instanceX = childList.get(0).getMeasuredWidth() + MARGIN;
        instanceY = getMeasuredHeight() - menuHeight;
        int translateX = instanceX / 2;

        holder0 = PropertyValuesHolder.ofFloat("translationX", -translateX, 0);
        holder1 = PropertyValuesHolder.ofFloat("translationY", -instanceY, 0);
        holder2 = PropertyValuesHolder.ofFloat("scaleX", 1, 0.5f);
        holder3 = PropertyValuesHolder.ofFloat("scaleY", 1, 0.5f);
        holder4 = PropertyValuesHolder.ofFloat("alpha", 1, 0f);
        closeLeft = ObjectAnimator.ofPropertyValuesHolder(childList.get(0), holder0, holder1, holder2, holder3, holder4);
        closeLeft.addListener(this);
        closeLeft.setDuration(2000);
        holder00 = PropertyValuesHolder.ofFloat("translationX", translateX, 0);
        closeRight = ObjectAnimator.ofPropertyValuesHolder(childList.get(1), holder00, holder1, holder2, holder3, holder4);
        closeRight.setDuration(2000);
        //还原
        holderN0 = PropertyValuesHolder.ofFloat("translationX", 0, -translateX);
        holderN1 = PropertyValuesHolder.ofFloat("translationY", 0, -instanceY);
        holderN2 = PropertyValuesHolder.ofFloat("scaleX", 0.5f, 1f);
        holderN3 = PropertyValuesHolder.ofFloat("scaleY", 0.5f, 1f);
        holderN4 = PropertyValuesHolder.ofFloat("alpha", 0f, 1f);

        openLeft = ObjectAnimator.ofPropertyValuesHolder(childList.get(0), holderN0, holderN1, holderN2, holderN3, holderN4);
        openLeft.addListener(this);
        openLeft.setDuration(2000);
        PropertyValuesHolder holderN00 = PropertyValuesHolder.ofFloat("translationX", 0, translateX);
        openRight = ObjectAnimator.ofPropertyValuesHolder(childList.get(1), holderN00, holderN1, holderN2, holderN3, holderN4);
        openRight.setDuration(2000);
    }

    public void docloes() {
//当当前View正在动画的时候,是不允许再次动画的
        if (isAnimationing)return;
        closeLeft.start();
        closeRight.start();
        model = CLOSE;
    }
 public void doOpen() {
        if (isAnimationing)return;
        openLeft.start();
        openRight.start();
        model = OPEN;
    }

好了,关键代码就是这些,要注意,何时init,这个时机很重要,当init有addView操作的,那么就必须放在onFinishLayoutInflate()方法中,原因是当从xm中加载完毕后,我们的ViewGroup才被创建,所以要在该方法中取添加或者操作子View,还有一点,就是在第一次动画的时候,要找准动画的时机,不然有一些数据还未初始化,就要开始动画了,这样会出现各种错误。好了,基本就是这么多,有兴趣的可以去下载源码看看GitHub地址https://github.com/yzzAndroid/Animator

原文链接:http://www.apkbus.com/blog-822415-68297.html

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/3153/viewspace-2814175/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2019-08-30

  • 博文量
    0
  • 访问量
    737