28
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

AndroidAdvent Calendar 2016

Day 1

Viewのanimateメソッドで動きのあるアプリへ!

Last updated at Posted at 2016-12-01

もう本当にAnmationを簡単に実装したい時は、これに限ると思ってます!

スケールを大きくする

// Scale Focusが当たった時やTapした時など
// XとYの大きさが100msかけて大きくなる
textView.animate().scaleX(2f).scaleY(2f).setDuration(1000);

ふわっと出す

// Splash向け 1200msかけて透明度が0になる 1が透明度なし 0が透明です
// 0.8fが80パーセントの透明度
textView.animate().alpha(0f).setDuration(1200);

SwipeRefreshLayoutを引っ張り更新の際にとかやると綺麗

// Viewの更新がかかった後など
listView.setAlpha(0f);
listView.animate().alpha(1f).setDuration(300);

移動

// 500msかけてxとyが100ピクセル移動する
textView.animate().x(100).y(100).setDuration(500);

回転する

// Rotation トーグルを回転させる時の動きなどに! 1000msかけて1回転する
// 180なら半回転
textView.animate().rotation(360).setDuration(1000);

Animationが始まった時や終わった時のリスナーをつける

// scaleがXとY二倍になった後
textView.animate().scaleX(2f).scaleY(2f).setDuration(1000).setListener(new Animator.AnimatorListener() {
  @Override
  public void onAnimationStart(Animator animator) {
  }

  @Override
  public void onAnimationEnd(Animator animator) {
    textView.animate().scaleX(1f).scaleY(1f).setDuration(2000);
  }

  @Override
  public void onAnimationCancel(Animator animator) {
  }

  @Override
  public void onAnimationRepeat(Animator animator) {
  }
});

実際にアプリに組み込んでみるとこんな感じ

タップすると動画プレイヤーを大きくする・小さくするをします
scaleX scaleY x y setDuration alpha を使っています
Youtubeみたい!
※ 動画の再生には、ExoPlayerを使っています
emu.gif

ソースはこちら


import android.content.pm.ActivityInfo;
import android.databinding.DataBindingUtil;
import android.graphics.SurfaceTexture;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.FragmentActivity;
import android.view.TextureView;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.webkit.WebView;

import com.google.android.exoplayer2.DefaultLoadControl;
import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.LoadControl;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.source.hls.HlsMediaSource;
import com.google.android.exoplayer2.trackselection.AdaptiveVideoTrackSelection;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelector;
import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;

import java.util.Timer;
import java.util.TimerTask;

import jp.logiclogic.recycler_in_exoplayer.R;
import jp.logiclogic.recycler_in_exoplayer.databinding.ExoPlayerAnimationLayoutBinding;

/**
 * Created by ueno-yuuhei on 2016/11/12.
 */
public class ExoPlayerAnimationActivity extends FragmentActivity implements TextureView.SurfaceTextureListener {
    private ExoPlayerAnimationLayoutBinding binding; // DataBinging
    private SimpleExoPlayer simpleExoPlayer; // ExoPlayer
    private Timer playerTimer; // プレイヤー監視

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.exo_player_animation_layout);

        // 横固定
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        // ステータスバー非表示
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        // ナビゲーションバー非表示
        View decor = getWindow().getDecorView();
        if (Build.VERSION.SDK_INT > 18) {
            decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
        } else if (Build.VERSION.SDK_INT > 15) {
            decor.setSystemUiVisibility(
                    View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN);
        } else if (Build.VERSION.SDK_INT > 13) {
            decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
        } else {
            decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
        }

        // ViewTreeObserverでプレイヤー領域の大きさを確保してから右下にAnimation
        binding.textureViewArea.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                if (binding.textureViewArea.getWidth() > 0 && binding.textureViewArea.getWidth() > 0) {
                    binding.textureViewArea.animate()
                            .scaleX(0.3f)
                            .scaleY(0.3f)
                            .x((float) (binding.textureViewArea.getWidth() / 3))
                            .y((float) (binding.textureViewArea.getHeight() / 3))
                            .setDuration(100);
                    binding.playerTime.animate().setDuration(100).alpha(0f);
                    binding.textureViewArea.setTag(true);
                    if (Build.VERSION.SDK_INT >= 16) {
                        binding.textureViewArea.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                    } else {
                        binding.textureViewArea.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                    }
                }
            }
        });
        binding.textureView.setSurfaceTextureListener(this);
        binding.textureViewArea.setTag(true);

        // プレイヤー領域をTapしたらAnimationで右下に動くように
        binding.textureViewArea.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                boolean toggle = (Boolean) view.getTag();
                if (toggle) {
                    binding.textureViewArea.animate().scaleX(1f).scaleY(1f).x(0).y(0).setDuration(100);
                    binding.playerTime.animate().setDuration(100).alpha(1f);
                } else {
                    binding.textureViewArea.animate().scaleX(0.3f).scaleY(0.3f)
                            .x((float) (binding.textureViewArea.getWidth() / 3))
                            .y((float) (binding.textureViewArea.getHeight() / 3))
                            .setDuration(100);
                    binding.playerTime.animate().setDuration(100).alpha(0f);
                }
                view.setTag(!toggle);
            }
        });
    }

    @Override
    protected void onResume() {
        super.onResume();

        if (simpleExoPlayer != null) {
            starPlayerTimer();
            simpleExoPlayer.setPlayWhenReady(true);
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        stopPlayerTimer();

        if (simpleExoPlayer != null) {
            simpleExoPlayer.setPlayWhenReady(false);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

    // 秒数をセット
    private void starPlayerTimer() {
        stopPlayerTimer();
        playerTimer = new Timer();
        playerTimer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                binding.playerTime.post(new Runnable() {
                    @Override
                    public void run() {
                        int duration = (int) (simpleExoPlayer.getDuration() / 1000);
                        int current = (int) (simpleExoPlayer.getCurrentPosition() / 1000);
                        String time = getMinuteSecond(current) + " / " + getMinuteSecond(duration);
                        binding.playerTime.setText(time);
                        binding.imageTime.setText(time);
                    }
                });
            }
        }, 1000, 1000);
    }

    private String getMinuteSecond(int totalSecond) {
        int minute = totalSecond / 60;
        int second = totalSecond % 60;
        return String.format("%02d", minute) + ":" + String.format("%02d", second);
    }

    private void stopPlayerTimer() {
        if (playerTimer != null) {
            playerTimer.purge();
            playerTimer.cancel();
            playerTimer = null;
        }
    }

    // ------ ExoPlayer ------
    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) {
        Handler mainHandler = new Handler();
        BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
        TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveVideoTrackSelection.Factory(bandwidthMeter);
        TrackSelector trackSelector = new DefaultTrackSelector(mainHandler, videoTrackSelectionFactory);
        LoadControl loadControl = new DefaultLoadControl();
        simpleExoPlayer = ExoPlayerFactory.newSimpleInstance(getApplicationContext(), trackSelector, loadControl);
        simpleExoPlayer.setVideoTextureView(binding.textureView);

        DefaultBandwidthMeter defaultBandwidthMeter = new DefaultBandwidthMeter();
        DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(this,
                com.google.android.exoplayer2.util.Util.getUserAgent(this, new WebView(getApplicationContext()).getSettings().getUserAgentString()), defaultBandwidthMeter);
        simpleExoPlayer.prepare(getHlsMediaSource("http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8", dataSourceFactory, mainHandler));
        simpleExoPlayer.setPlayWhenReady(true);
        starPlayerTimer();
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) {

    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
        return false;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {

    }

    private HlsMediaSource getHlsMediaSource(String videoUrl, DataSource.Factory dataSourceFactory, Handler mainHandler) {
        return new HlsMediaSource(Uri.parse(videoUrl),
                dataSourceFactory,
                mainHandler, null);
    }
    // ------ ExoPlayer ------
}

レイアウトファイル

<layout>

    <FrameLayout 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:background="#222"
        tools:context=".activity.ExoPlayerActivity">

        <TextView
            android:id="@+id/image_time"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="top|right"
            android:layout_margin="16dp"
            android:textColor="#FFF"
            android:textSize="16sp" />

        <FrameLayout
            android:id="@+id/texture_view_area"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <TextureView
                android:id="@+id/texture_view"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />

            <TextView
                android:id="@+id/player_time"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="bottom|right"
                android:layout_margin="16dp"
                android:textColor="#FFF"
                android:textSize="16sp" />
        </FrameLayout>
    </FrameLayout>

</layout>
28
22
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?