今天来写一个淘宝的一个小动画,一看觉得挺简单的,但是实际操作起来,感觉有点麻烦,遇到的问题也比较多,不过好在模仿出来了,好了给大家看看效果。 这是老版本的,模拟器上面的和现版本的不一致 这个是新版本的,下面的布局Bi老版本要稍微复杂一点。 接下
今天来写一个淘宝的一个小动画,一看觉得挺简单的,但是实际操作起来,感觉有点麻烦,遇到的问题也比较多,不过好在模仿出来了,好了给大家看看效果。
这是老版本的,模拟器上面的和现版本的不一致
这个是新版本的,下面的布局Bi老版本要稍微复杂一点。
接下来看看主界面的布局结构,最外面的是一个ViewGroup,然后就是一个“+”的View,再就是文本。
下面我们就来完成这个View的书写,先定义一个ViewGroup,在定义一个View画上“+”,然后ViewGroup里面加上该View和文本内容。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
RectF rectF = new RectF(0,0,getMeasuredWidth(),getMeasuredHeight()/2);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
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) {
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
);
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
由于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);
}
});
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
以上还只是完成了最基本的步骤,“+”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不太了解的可以看看我的第一篇博客WindowManger的应用
public class MyWindow {
private WindowManager mWindowManager;
private WindowManager.LayoutParams mLp;
private Activity context;
private View view;
public MyWindow(Activity context) {
this.context = context;
mWindowManager = context.getWindowManager();
mLp = new WindowManager.LayoutParams();
mLp.height = WindowManager.LayoutParams.MATCH_PARENT;
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;
}
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
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<String> 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
View v = myAnimatorView.getChildAt(i)
final int finalI = i
v.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,list.get(finalI),Toast.LENGTH_LONG).show()
}
})
}
myMenuView.setClickListener(new MyMenuView.ClickListener() {
@Override
public void click(View view) {
//这里我是在点击事件里面设置给Window上的View的init数据的,这里只设置一次
if (isFirst) {
isFirst = false
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) myAnimatorView.getLayoutParams()
//高度的话我们这里要设置到,必须在一级菜单的上方。
lp.height = myMenuView.getMeasuredHeight() + myMenuView.getWidth() / 2 + MyAnimatorView.MARGIN
myAnimatorView.setLayoutParams(lp)
myAnimatorView.setRadius(myMenuView.getWidth() / 2)
//设置上去菜单的高度,后面平移动画需要 myAnimatorView.setHeight(myMenuView.getHeight())
myWindow.addView(contentView)
} else {
myWindow.addView(contentView)
//myAnimatorView.doOpen()
}
}
})
contentView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myMenuView.change(MyMenuView.TO_NOMAL)
myAnimatorView.docloes()
}
})
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
接下来我们要初始化myAnimatorView了。
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (radius <= 0) return;
int count = getChildCount();
int h = getMeasuredHeight() - menuHeight;
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
child.layout(instanceX / 2, h, instanceX / 2 + child.getMeasuredWidth(), h + child.getMeasuredHeight());
child.setScaleX(0.5f);
child.setScaleY(0.5f);
child.setAlpha(0f);
}
doOpen();
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
这里使用的属性动画,属性动画的有点就是在动画的过程中改变了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
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
好了,关键代码就是这些,要注意,何时init,这个时机很重要,当init有addView操作的,那么就必须放在onFinishLayoutInflate()方法中,原因是当从xm中加载完毕后,我们的ViewGroup才被创建,所以要在该方法中取添加或者操作子View,还有一点,就是在第一次动画的时候,要找准动画的时机,不然有一些数据还未初始化,就要开始动画了,这样会出现各种错误。好了,基本就是这么多,有兴趣的可以去下载源码看看GitHub地址https://github.com/yzzAndroid/Animator
淘宝首页动画的实现
转载https://www.codesocang.com/appboke/36423.html