简要介绍
本文是参考请叫我大苏的博客,写的非常实用,这里主要是记录这个实例方便以后自己的使用,同时也在项目中遇到的疑惑贴出来,希望有人能帮忙解答一下,大家共同学习,谢谢。
demo介绍
本demo实现的就两个功能,一个竖直方向扩展图片,一个呈圆弧状扩展图片。图片如下:
这里两个demo,主要是写一点实用的业务,避免以后到处查找,方便自己借鉴。
demo步骤
首先导入依赖:
compile ‘com.jakewharton:butterknife:5.1.1’
先在res文件夹下,创建animator文件夹,并创建一个round_show.xml动画,具体代码如下:
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:propertyName="alpha"
android:valueFrom="0f"
android:valueTo="1f"
android:valueType="floatType">
</objectAnimator>
demo的布局文件如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="bottom|left"
android:orientation="vertical">
<ImageView
android:id="@+id/img_home1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/bg_img"
android:layout_margin="3dp"
android:clickable="true"
android:src="@drawable/ic_home_white_48dp"/>
<ImageView
android:id="@+id/img_refresh1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="3dp"
android:background="@drawable/bg_img"
android:clickable="true"
android:src="@drawable/ic_refresh_white_48dp"/>
<ImageView
android:id="@+id/img_clear1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="3dp"
android:clickable="true"
android:background="@drawable/bg_img"
android:src="@drawable/ic_clear_white_48dp"/>
<ImageView
android:id="@+id/img_back1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="3dp"
android:clickable="true"
android:background="@drawable/bg_img"
android:src="@drawable/ic_chevron_left_white_48dp"/>
<ImageView
android:id="@+id/img_next1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/bg_img"
android:layout_margin="3dp"
android:clickable="true"
android:src="@drawable/ic_navigate_next_white_48dp"/>
<ImageView
android:id="@+id/img_down_up1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="3dp"
android:background="@drawable/bg_img"
android:clickable="true"
android:src="@drawable/ic_arrow_drop_down_white_48dp"/>
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom|center"
android:layout_marginLeft="50dp">
<ImageView
android:id="@+id/img_home2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="3dp"
android:clickable="true"
android:background="@drawable/bg_img"
android:src="@drawable/ic_home_white_48dp"/>
<ImageView
android:id="@+id/img_refresh2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="3dp"
android:clickable="true"
android:background="@drawable/bg_img"
android:src="@drawable/ic_refresh_white_48dp"/>
<ImageView
android:id="@+id/img_clear2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="3dp"
android:clickable="true"
android:background="@drawable/bg_img"
android:src="@drawable/ic_clear_white_48dp"/>
<ImageView
android:id="@+id/img_back2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="3dp"
android:clickable="true"
android:background="@drawable/bg_img"
android:src="@drawable/ic_chevron_left_white_48dp"/>
<ImageView
android:id="@+id/img_next2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:background="@drawable/bg_img"
android:src="@drawable/ic_navigate_next_white_48dp"/>
<ImageView
android:id="@+id/img_down_up2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="3dp"
android:clickable="true"
android:background="@drawable/bg_img"
android:src="@drawable/ic_arrow_drop_up_white_48dp"/>
</RelativeLayout>
</RelativeLayout>
然后直接在MainActiity中实现动画效果,具体看注释。代码如下:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.inject(this);
downUpIcon2.performClick();
}
@InjectView(R.id.img_home1)
ImageView homeIcon1;
@InjectView(R.id.img_home2)
ImageView homeIcon2;
@InjectView(R.id.img_refresh1) ImageView refreshIcon1;
@InjectView(R.id.img_refresh2) ImageView refreshIcon2;
@InjectView(R.id.img_clear1) ImageView clearIcon1;
@InjectView(R.id.img_clear2) ImageView clearIcon2;
@InjectView(R.id.img_back1) ImageView backIcon1;
@InjectView(R.id.img_back2) ImageView backIcon2;
@InjectView(R.id.img_next1) ImageView nextIcon1;
@InjectView(R.id.img_next2) ImageView nextIcon2;
@InjectView(R.id.img_down_up1) ImageView downUpIcon1;
@InjectView(R.id.img_down_up2) ImageView downUpIcon2;
//垂直方向上的图片是否隐藏
private boolean isIconHided1 = false;
//圆弧方向上的图片是否隐藏
private boolean isIconHided2 = false;
//是否计算了图片间的间距,(间距方便设置动画)
private boolean isIconCalculate = false;
//垂直方向标识
private static final int VERTIAL_ANIM = 1;
//圆弧方向标识
private static final int ROUND_ANIM = 2;
//垂直图标点击事件
@OnClick(R.id.img_down_up1)
public void mDownUpClick(){
if (isIconHided1){
//展示垂直方向上的图片动画
showIcons(VERTIAL_ANIM);
//改变点击图标
downUpIcon1.setImageResource(R.drawable.ic_arrow_drop_down_white_48dp);
}else {
//隐藏垂直方向上的图片动画
hideIcons(VERTIAL_ANIM);
//改变点击图标
downUpIcon1.setImageResource(R.drawable.ic_arrow_drop_up_white_48dp);
}
isIconHided1 = !isIconHided1;
}
//圆弧图标点击事件
@OnClick(R.id.img_down_up2)
public void mDownUpClick2(){
if (isIconHided2){
//展示圆弧方向上的图片动画
showIcons(ROUND_ANIM);
//改变点击图标
downUpIcon2.setImageResource(R.drawable.ic_arrow_drop_down_white_48dp);
}else {
//隐藏圆弧方向上的图片动画
hideIcons(ROUND_ANIM);
//改变点击图标
downUpIcon2.setImageResource(R.drawable.ic_arrow_drop_up_white_48dp);
}
isIconHided2 = !isIconHided2;
}
//设置图片展示的动画
private void showIcons(final int anim){
if (anim == VERTIAL_ANIM){
verialShowAnim(homeIcon1);
verialShowAnim(refreshIcon1);
verialShowAnim(clearIcon1);
verialShowAnim(backIcon1);
verialShowAnim(nextIcon1);
}else if (anim == ROUND_ANIM){
//以半径为300的圆形区域扩展
float radius = 300f;
//半径除以根号2
float offset = radius / (float)Math.sqrt(2);
ObjectAnimator animator = ObjectAnimator.ofFloat(homeIcon2,"translationX",-radius);
ObjectAnimator animator1 = ObjectAnimator.ofFloat(refreshIcon2,"translationX",-offset);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(refreshIcon2,"translationY",-offset);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(clearIcon2,"translationY",-radius);
ObjectAnimator animator4 = ObjectAnimator.ofFloat(backIcon2,"translationX",offset);
ObjectAnimator animator5 = ObjectAnimator.ofFloat(backIcon2,"translationY",-offset);
ObjectAnimator animator6 = ObjectAnimator.ofFloat(nextIcon2,"translationX",radius);
roundShowAima(homeIcon2);
roundShowAima(clearIcon2);
roundShowAima(refreshIcon2);
roundShowAima(backIcon2);
roundShowAima(nextIcon2);
AnimatorSet set = new AnimatorSet();
set.setDuration(1000);
//组合动画展示
set.play(animator).with(animator1).with(animator2)
.with(animator3).with(animator4).with(animator5).with(animator6);
set.start();
}
}
//隐藏动画
private void hideIcons(int anim){
if (anim == VERTIAL_ANIM){
//竖直收缩动画需要计算icon要平移的距离
if (!isIconCalculate){
//将计算出来的竖直距离存起来,方便设置动画时使用
homeIcon1.setTag(calculateWidgetsDistance(homeIcon1,downUpIcon1)[1]);
refreshIcon1.setTag(calculateWidgetsDistance(refreshIcon1,downUpIcon1)[1]);
clearIcon1.setTag(calculateWidgetsDistance(clearIcon1,downUpIcon1)[1]);
backIcon1.setTag(calculateWidgetsDistance(backIcon1,downUpIcon1)[1]);
nextIcon1.setTag(calculateWidgetsDistance(nextIcon1,downUpIcon1)[1]);
isIconCalculate = true;
}
//使用ValueAnimator,为了了解它的更多用法,这里将用多种方式来达到动画效果
ValueAnimator animator = ValueAnimator.ofFloat(0.0f,1.0f);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
//竖直平移动画
float transY;
transY = ((int) homeIcon1.getTag()) * value;
homeIcon1.setTranslationY(transY);
transY = ((int) refreshIcon1.getTag()) * value;
refreshIcon1.setTranslationY(transY);
transY = ((int) clearIcon1.getTag()) * value;
clearIcon1.setTranslationY(transY);
transY = ((int) backIcon1.getTag()) * value;
backIcon1.setTranslationY(transY);
}
});
ValueAnimator animator1 = ValueAnimator.ofFloat(0.0f,((int)nextIcon1.getTag()));
animator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
nextIcon1.setTranslationY(value);
}
});
//从不透明到完全透明
ValueAnimator animator2 = ValueAnimator.ofFloat(1.0f,0.0f);
animator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
homeIcon1.setAlpha(value);
refreshIcon1.setAlpha(value);
clearIcon1.setAlpha(value);
backIcon1.setAlpha(value);
nextIcon1.setAlpha(value);
}
});
animator.setDuration(1000);
animator1.setDuration(1000);
animator2.setDuration(200);
AnimatorSet set = new AnimatorSet();
set.play(animator).with(animator1).before(animator2);
set.start();
}else if (anim == ROUND_ANIM){
roundHideAnim(homeIcon2);
roundHideAnim(refreshIcon2);
roundHideAnim(clearIcon2);
roundHideAnim(backIcon2);
roundHideAnim(nextIcon2);
}
}
private void verialShowAnim(View view){
//0,表示view的Y坐标从当前位置平移到最初最初的位置
ObjectAnimator animator = ObjectAnimator.ofFloat(view,"translationY",0);
ObjectAnimator animator1 = ObjectAnimator.ofFloat(view,"alpha",1);
animator.setDuration(1000);
animator1.setDuration(1000);
animator.start();
animator1.start();
View view1;
}
//圆弧隐藏
private void roundHideAnim(View view){
ObjectAnimator animator = ObjectAnimator.ofFloat(view,"translationX",0);
ObjectAnimator animator1 = ObjectAnimator.ofFloat(view,"translationY",0);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(view,"alpha",0);
AnimatorSet set = new AnimatorSet();
set.setDuration(1000);
set.play(animator).with(animator1).with(animator2);
set.start();
}
private void roundShowAima(View view){
ObjectAnimator animator7 = (ObjectAnimator) AnimatorInflater.loadAnimator(this,R.animator.round_show);
animator7.setTarget(view);
animator7.start();
}
/**
* 计算两个view的距离
* @param v1
* @param v2
* @return 返回new int[2], [0]横坐标距离,[1]纵坐标的距离
*/
private int[] calculateWidgetsDistance(View v1, View v2){
int[] location1 = new int[2];
int[] location2 = new int[2];
int[] ret = new int[2];
v1.getLocationOnScreen(location1);
v2.getLocationOnScreen(location2);
ret[0] = Math.abs(location1[0] - location2[0]);
ret[1] = Math.abs(location1[1] - location2[1]);
return ret;
}
}
以上就是一个完整的demo实现,比较简单,仅供大家一起来学习,也再次感谢请叫我大苏。
一点疑惑,希望有人解答
这里是另外一个自己写的测试demo,布局文件主要注意几点,后面会有疑问(1,这里整体是线性布局,第一个子线性布局高度已经用了matchparent。2,第一个子线程布局下有一个Button隐藏在了界面下方,初始时,界面上看不见。3,Button下有一个线程布局,且该线性布局的高度是WrapContent,在界面上仍然看不到)布局文件如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context="com.example.lfq.MainActivity">
<LinearLayout
android:id="@+id/ly_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/bt_1"
android:layout_width="match_parent"
android:layout_height="40dp"
android:onClick="onClick"
android:text="点击弹出" />
<Button
android:layout_below="@id/bt_1"
android:layout_width="match_parent"
android:layout_height="40dp"
android:text="hello"/>
</LinearLayout>
<Button
android:id="@+id/bt_4"
android:layout_width="match_parent"
android:layout_height="40dp"
android:onClick="onClick"
android:text="点击弹出" />
<LinearLayout
android:id="@+id/ly_show"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tv_content1"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:onClick="onClick1"
android:text="test content 1"
android:textColor="#4a4a4a"
android:textSize="16sp" />
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#e0e0e0" />
<TextView
android:id="@+id/tv_content2"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:onClick="onClick2"
android:text="test content 2"
android:textColor="#4a4a4a"
android:textSize="16sp" />
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#e0e0e0" />
<TextView
android:id="@+id/tv_content3"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:onClick="onClick3"
android:text="test content 3"
android:textColor="#4a4a4a"
android:textSize="16sp" />
</LinearLayout>
</LinearLayout>
再贴出MainActivity的控制动画界面。比较简单,只为了测试:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//第二个子线性布局(隐藏在界面下方,界面上看不到)
ly_show = (LinearLayout) findViewById(R.id.ly_show);
//第二个子线性布局中的一个子控件
tv=(TextView) findViewById(R.id.tv_content1);
//隐藏在第一个子线性布局下的BUtton
bt = (Button) findViewById(R.id.bt_4);
//第一个子线性布局中的Button
bt2 = (Button) findViewById(R.id.bt_1);
}
public void onClick(View view) {
// float curTranslation = tv.getTranslationY();
//float height=ly_show.getHeight();
ObjectAnimator//
//界面来我们测试的主要内容就是第一个参数,也就是下面的ly_show位置
.ofFloat(ly_show, "translationY", 0.0F, -360.0F, 0.0F)//
.setDuration(500)//
.start();
}
}
(1)效果:我们依次将动画的对象,也就是上面注释中说到的ly_show位置那个参数替换为tv、bt、bt2。
这里我们会发现真正有正常动画的也就是bt以及bt2,而tv以及ly_show不会产生动画效果,弹不出来。
(2)改变:我们将第二个子线性布局中的高度wrapcontent改为一个固定的值200dp,然后测试,会出现动画效果。但是tv仍然没有动画效果。
(3)将整体的线性布局改为帧布局,将第二个子线性布局高度设置为wrapcontent会发现能正常动画,但是界面很丑。
(4)将整体改为Relativilayout,,用layout_below将原来的bt_4隐藏到界面下面,然后对这个Button进行动画测试,发现并没有动画效果。
其实还有很多可以测试的地方,大家慢慢体验,关键问题就是属性对话与布局间存在的冲突关系搞不清楚,希望有大拿帮忙解答一下,谢谢。