ViewAnimationUtils.createCircularReveal() は、Viewを円形にくり抜くアニメーション(Animator)を作るユーティリティメソッドです。 例えばこんな感じ。
public class SampleActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sample);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final View container = findViewById(R.id.container);
final int width = container.getWidth();
final int height = container.getHeight();
float startRadius = (float) Math.sqrt(width * width + height * height) / 2;
float endRadius = 0;
final Animator animator = ViewAnimationUtils.createCircularReveal(container,
width / 2, height / 2, startRadius, endRadius);
animator.setDuration(3000);
animator.start();
}
});
}
}
FAB の transforming
https://material.google.com/components/buttons-floating-action-button.html#buttons-floating-action-button-transitions の真ん中あたり、toolbar という項目のやつです。
アニメーション以外の本質的なコードは toolsContainer と fab の visibility の切り替えだけ(以下の部分)なんですけど、アニメーションのコード入れると長い...
toolsContainer.setVisibility(View.VISIBLE);
fab.setVisibility(View.INVISIBLE);
これが全体のコードなのですが、長いですね...
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final View toolsContainer = findViewById(R.id.tools_container);
final View tools = findViewById(R.id.tools);
final FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
final ToggleButton toggleButton = (ToggleButton) findViewById(R.id.button);
toggleButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
final int fabWidth = fab.getWidth();
final int fabHeight = fab.getHeight();
final int toolsWidth = toolsContainer.getWidth();
final int toolsHeight = toolsContainer.getHeight();
float startRadius = fabHeight / 2f;
float endRadius = (float) (Math.sqrt(toolsWidth * toolsWidth + toolsHeight * toolsHeight));
int[] outLocation = new int[2];
toolsContainer.getLocationInWindow(outLocation);
int[] fabOutLocation = new int[2];
fab.getLocationInWindow(fabOutLocation);
float diff = isChecked
? (outLocation[1] + toolsHeight / 2) - (fabOutLocation[1] + fabHeight / 2)
: 0;
int centerX = (int) (fabOutLocation[0] + fabWidth / 2 - outLocation[0] - diff);
int centerY = toolsHeight / 2;
final int FAB_DURATION = 100;
final int TOOLS_DURATION = 300;
if (isChecked) {
final Animator fabAnimator1 = ObjectAnimator.ofFloat(fab, "translationY", diff);
fabAnimator1.setDuration(FAB_DURATION);
fabAnimator1.setInterpolator(new DecelerateInterpolator());
final Animator fabAnimator2 = ObjectAnimator.ofFloat(fab, "translationX", -diff);
fabAnimator2.setDuration(FAB_DURATION);
fabAnimator2.setInterpolator(new AccelerateInterpolator());
final ValueAnimator fabAnimator3 = ValueAnimator.ofInt(255, 0);
fabAnimator3.setDuration(FAB_DURATION);
fabAnimator3.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
final int alpha = (int) animation.getAnimatedValue();
final Drawable drawable = fab.getDrawable();
drawable.setAlpha(alpha);
}
});
final Animator toolsContainerAnimator = ViewAnimationUtils.createCircularReveal(toolsContainer,
centerX, centerY, startRadius, endRadius);
toolsContainerAnimator.setDuration(TOOLS_DURATION);
toolsContainerAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
toolsContainer.setVisibility(View.VISIBLE);
fab.setVisibility(View.INVISIBLE);
}
});
tools.setPivotX(centerX);
final Animator toolsAnimator = ObjectAnimator.ofPropertyValuesHolder(tools,
PropertyValuesHolder.ofFloat("alpha", 0f, 1f),
PropertyValuesHolder.ofFloat("scaleX", 0.8f, 1f));
toolsAnimator.setDuration(TOOLS_DURATION);
AnimatorSet set = new AnimatorSet();
set.play(toolsContainerAnimator).with(toolsAnimator)
.after(fabAnimator1).after(fabAnimator2).after(fabAnimator3);
set.start();
} else {
final Animator fabAnimator1 = ObjectAnimator.ofFloat(fab, "translationY", 0);
fabAnimator1.setDuration(FAB_DURATION);
fabAnimator1.setInterpolator(new AccelerateInterpolator());
final Animator fabAnimator2 = ObjectAnimator.ofFloat(fab, "translationX", 0);
fabAnimator2.setDuration(FAB_DURATION);
fabAnimator2.setInterpolator(new DecelerateInterpolator());
final ValueAnimator fabAnimator3 = ValueAnimator.ofInt(0, 255);
fabAnimator3.setDuration(FAB_DURATION);
fabAnimator3.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
final int alpha = (int) animation.getAnimatedValue();
final Drawable drawable = fab.getDrawable();
drawable.setAlpha(alpha);
}
});
final Animator toolsContainerAnimator = ViewAnimationUtils.createCircularReveal(
toolsContainer, centerX, centerY, endRadius, startRadius);
toolsContainerAnimator.setDuration(TOOLS_DURATION);
toolsContainerAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
toolsContainer.setVisibility(View.INVISIBLE);
fab.setVisibility(View.VISIBLE);
}
});
tools.setPivotX(centerX);
final Animator toolsAnimator = ObjectAnimator.ofPropertyValuesHolder(tools,
PropertyValuesHolder.ofFloat("alpha", 0f),
PropertyValuesHolder.ofFloat("scaleX", 0.8f));
toolsAnimator.setDuration(TOOLS_DURATION);
AnimatorSet set = new AnimatorSet();
set.play(toolsContainerAnimator).with(toolsAnimator)
.before(fabAnimator1).before(fabAnimator2).before(fabAnimator3);
set.start();
}
}
});
toolsContainer.setVisibility(toggleButton.isChecked() ? View.VISIBLE : View.INVISIBLE);
tools.setAlpha(toggleButton.isChecked() ? 1f : 0f);
}
}
アニメーションの長いコードがあるために、ここでやっていること(つまり toolsContainer と fab の visibility を切り替えること)がわかりにくくなっています。
それを解消するために Transition API が使えます(Transition API はもともとそういうための用意されたもののようです)。それは次回に。
↓実行結果
0 件のコメント:
コメントを投稿