android – RaHaprogramming

Android – Working with XML Animations

Adding animations to your app interface will give high quality feel to your android applications. Animations can be performed through either XML or android code. In this tutorial i explained how to do animations using XML notations. I will explain how to do the same using android java code in future tutorials. Here i covered basic android animations like fade in, fade out, scale, rotate, slide up, slide down etc.

In the source code project provided in this tutorial, I wrote separate activity and XML for each animation. Download and play with the code to get familiar with the animations. Following are list of animations covered in this article.

android animations using xml

Basic steps to perform animation

Following are the basic steps to perform an animation on any UI element. Creating animation is very simple, all it needs is creating necessary files and write small pieces of code.

Step 1: Create xml that defines the animation

Create an xml file which defines type of animation to perform. This file should be located under anim folder under res directory (res ⇒ anim ⇒ animation.xml). If you don’t have anim folder in your res directory create one. Following is example of simple fade in animation.

android animation anim folder

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"android:fillAfter="true" > 

<alpha android:duration="1000"android:fromAlpha="0.0"android:interpolator="@android:anim/accelerate_interpolator"android:toAlpha="1.0" />

 </set>

Step 2: Load the animation

Next in your activity create an object of Animation class. And load the xml animation using AnimationUtils by calling loadAnimation function.

public class FadeInActivity extends Activity{

    TextView txtMessage;

    // Animation

    Animation animFadein;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_fadein);

        txtMessage = (TextView) findViewById(R.id.txtMessage);

        // load the animation

        animFadein = AnimationUtils.loadAnimation(getApplicationContext(),

                R.anim.fade_in);       

    }

}

Step 3: Set the animation listeners (Optional)

If you want to listen to animation events like start, end and repeat, your activity should implements AnimationListener. This step is optional. If you implement AnimationListener you will have to override following methods.

onAnimationStart – This will be triggered once the animation started
onAnimationEnd – This will be triggered once the animation is over
onAnimationRepeat – This will be triggered if the animation repeats

public class FadeInActivity extends Activity implements AnimationListener {

// set animation listener

animFadein.setAnimationListener(this);

// animation listeners

    @Override

    public void onAnimationEnd(Animation animation) {

        // Take any action after completing the animation

        // check for fade in animation

        if (animation == animFadein) {

            Toast.makeText(getApplicationContext(), “Animation Stopped”,

                    Toast.LENGTH_SHORT).show();

        }

    }

    @Override

    public void onAnimationRepeat(Animation animation) {

        // Animation is repeating

    }

    @Override

    public void onAnimationStart(Animation animation) {

        // Animation started

    }

Step 4: Finally start the animation

You can start animation whenever you want by calling startAnimation on any UI element by passing the type of animation. In this example i am calling fade in animation on TextView.

// start the animationtxtMessage.startAnimation(animFadein);

Complete Code

Following is complete code for FadeInActivity

public class FadeInActivity extends Activity implements AnimationListener {

    TextView txtMessage;

    Button btnStart;

    // Animation

    Animation animFadein;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        // TODO Auto-generated method stub

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_fadein);

        txtMessage = (TextView) findViewById(R.id.txtMessage);

        btnStart = (Button) findViewById(R.id.btnStart);

        // load the animation

        animFadein = AnimationUtils.loadAnimation(getApplicationContext(),

                R.anim.fade_in);

        // set animation listener

        animFadein.setAnimationListener(this);

        // button click event

        btnStart.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View v) {

                txtMessage.setVisibility(View.VISIBLE);

                // start the animation

                txtMessage.startAnimation(animFadein);

            }

        });

    }

    @Override

    public void onAnimationEnd(Animation animation) {

        // Take any action after completing the animation

        // check for fade in animation

        if (animation == animFadein) {

            Toast.makeText(getApplicationContext(), “Animation Stopped”,

                    Toast.LENGTH_SHORT).show();

        }

    }

    @Override

    public void onAnimationRepeat(Animation animation) {

        // TODO Auto-generated method stub

    }

    @Override

    public void onAnimationStart(Animation animation) {

        // TODO Auto-generated method stub

    }

}

Important XML animation attributes

When working with animations it is better to have through knowledge about some of the important XML attributes which create major differentiation in animation behavior. Following are the important attributes you must known about.

android:duration – Duration of the animation in which the animation should complete

android:startOffset – It is the waiting time before an animation starts. This property is mainly used to perform multiple animations in a sequential manner

android:interpolator – It is the rate of change in animation

android:fillAfter – This defines whether to apply the animation transformation after the animation completes or not. If it sets to false the element changes to its previous state after the animation. This attribute should be use with <set> node

android:repeatMode – This is useful when you want your animation to be repeat

android:repeatCount – This defines number of repetitions on animation. If you set this value to infinite then animation will repeat infinite times

Some useful animations

Following i am giving xml code to perform lot of useful animations. Try to assign different values to xml attributes to see change in animations.

1. Fade In
2. Fade Out
3. Cross Fading
4. Blink
5. Zoom In
6. Zoom Out
7. Rotate
8. Move
9. Slide Up
10. Slide Down
11. Bounce
12. Sequential Animation
13. Together Animation

Fade In

For fade in animation you can use <alpha> tag which defines alpha value. Fade in animation is nothing but increasing alpha value from 0 to 1.

fade_in.xml

<?xml version=”1.0″ encoding=”utf-8″?>

<set xmlns:android=”http://schemas.android.com/apk/res/android

    android:fillAfter=”true” >

    <alpha android:duration=”1000″  android:fromAlpha=”0.0″

        android:interpolator=”@android:anim/accelerate_interpolator”

        android:toAlpha=”1.0″ />

</set>

Fade Out

Fade out is exactly opposite to fade in, where we need to decrease the alpha value from 1 to 0

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"android:fillAfter="true" > <alphaandroid:duration="1000"android:fromAlpha="1.0"android:interpolator="@android:anim/accelerate_interpolator"android:toAlpha="0.0" /> 

</set>

Cross Fading

Cross fading is performing fade in animation while other element is fading out. For this you don’t have to create separate animation file, you can just use fade_in.xml and fade_out.xml files.

In the following code i loaded fade in and fade out, then performed them on two different UI elements.

TextView txtView1, txtView2;

Animation animFadeIn, animFadeOut;

// load animations

animFadeIn = AnimationUtils.loadAnimation(getApplicationContext(),

                R.anim.fade_in);

animFadeOut = AnimationUtils.loadAnimation(getApplicationContext(),

                R.anim.fade_out);

// set animation listeners

animFadeIn.setAnimationListener(this);

animFadeOut.setAnimationListener(this);

// Make fade in elements Visible first

txtMessage2.setVisibility(View.VISIBLE);

// start fade in animation

txtMessage2.startAnimation(animFadeIn);

// start fade out animation

txtMessage1.startAnimation(animFadeOut);

Blink animation is animating fade out or fade in animation in repetitive fashion. For this you will have to set android:repeatMode=”reverse” and android:repeatCount attributes.

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"><alpha android:fromAlpha="0.0"android:toAlpha="1.0"android:interpolator="@android:anim/accelerate_interpolator"android:duration="600"android:repeatMode="reverse"android:repeatCount="infinite"/></set>

Zoom In

For zoom use <scale> tag. Use pivotX=”50%” and pivotY=”50%” to perform zoom from the center of the element. Also you need to use fromXScalefromYScale attributes which defines scaling of the object. Keep these value lesser than toXScaletoYScale

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"android:fillAfter="true" > <scalexmlns:android="http://schemas.android.com/apk/res/android"android:duration="1000"android:fromXScale="1"android:fromYScale="1"android:pivotX="50%"android:pivotY="50%"android:toXScale="3"android:toYScale="3" ></scale>
 </set>

Zoom Out

Zoom out animation is same as zoom in but toXScaletoYScale values are lesser than fromXScalefromYScale

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"android:fillAfter="true" > <scalexmlns:android="http://schemas.android.com/apk/res/android"android:duration="1000"android:fromXScale="1.0"android:fromYScale="1.0"android:pivotX="50%"android:pivotY="50%"android:toXScale="0.5"android:toYScale="0.5" ></scale> 
</set>

Rotate

Rotate animation uses <rotate> tag. For rotate animation required tags are android:fromDegrees and android:toDegrees which defines rotation angles.

Clock wise – use positive toDegrees value
Anti clock wise – use negative toDegrees value

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"><rotate android:fromDegrees="0"android:toDegrees="360"android:pivotX="50%"android:pivotY="50%"android:duration="600"android:repeatMode="restart"android:repeatCount="infinite"android:interpolator="@android:anim/cycle_interpolator"/> </set>

Move

In order to change position of object use <translate> tag. It uses fromXDeltafromYDelta for X-direction and toXDeltatoYDelta attributes for Y-direction.

<?xml version="1.0" encoding="utf-8"?><setxmlns:android="http://schemas.android.com/apk/res/android"android:interpolator="@android:anim/linear_interpolator"android:fillAfter="true"> <translateandroid:fromXDelta="0%p"android:toXDelta="75%p"android:duration="800" /></set>

Slide Up

Sliding animation uses <scale> tag only. Slide up can be achieved by setting android:fromYScale=”1.0″ and android:toYScale=”0.0″

<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android"android:fillAfter="true" > <scaleandroid:duration="500"android:fromXScale="1.0"android:fromYScale="1.0"android:interpolator="@android:anim/linear_interpolator"android:toXScale="1.0"android:toYScale="0.0" /> </set>

Slide Down

Slide down is exactly opposite to slide down animation. Just interchange android:fromYScale and android:toYScale values.

<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android"android:fillAfter="true"> <scaleandroid:duration="500"android:fromXScale="1.0"android:fromYScale="0.0"android:interpolator="@android:anim/linear_interpolator"android:toXScale="1.0"android:toYScale="1.0" /> </set>

Bounce

Bounce is just an animation effect where animation ends in bouncing fashion. For this set android:interpolator value to @android:anim/bounce_interpolator. This bounce can be used with any kind animation. Following slide down example uses bounce effect.

<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android"android:fillAfter="true"android:interpolator="@android:anim/bounce_interpolator"> <scaleandroid:duration="500"android:fromXScale="1.0"android:fromYScale="0.0"android:toXScale="1.0"android:toYScale="1.0" /> </set>

Sequential Animation

If you want to perform multiple animation in a sequential manner you have to use android:startOffset to give start delay time. The easy way to calculate this value is to add the duration and startOffset values of previous animation. Following is a sequential animation where set of move animations performs in sequential manner.

<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android"android:fillAfter="true"android:interpolator="@android:anim/linear_interpolator" > <!-- Use startOffset to give delay between animations -->  <!-- Move --><translateandroid:duration="800"android:fillAfter="true"android:fromXDelta="0%p"android:startOffset="300"android:toXDelta="75%p" /><translateandroid:duration="800"android:fillAfter="true"android:fromYDelta="0%p"android:startOffset="1100"android:toYDelta="70%p" /><translateandroid:duration="800"android:fillAfter="true"android:fromXDelta="0%p"android:startOffset="1900"android:toXDelta="-75%p" /><translateandroid:duration="800"android:fillAfter="true"android:fromYDelta="0%p"android:startOffset="2700"android:toYDelta="-70%p" /> <!-- Rotate 360 degrees --><rotateandroid:duration="1000"android:fromDegrees="0"android:interpolator="@android:anim/cycle_interpolator"android:pivotX="50%"android:pivotY="50%"android:startOffset="3800"android:repeatCount="infinite"android:repeatMode="restart"android:toDegrees="360" /> </set>

Together Animation

Performing all animation together is just writing all animations one by one without using android:startOffset

<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android"android:fillAfter="true"android:interpolator="@android:anim/linear_interpolator" > <scalexmlns:android="http://schemas.android.com/apk/res/android"android:duration="4000"android:fromXScale="1"android:fromYScale="1"android:pivotX="50%"android:pivotY="50%"android:toXScale="4"android:toYScale="4" ></scale> <!-- Rotate 180 degrees --><rotateandroid:duration="500"android:fromDegrees="0"android:pivotX="50%"android:pivotY="50%"android:repeatCount="infinite"android:repeatMode="restart"android:toDegrees="360" /> </set>

I hope you like this tutorial, feel free to ask any kind of questions in the comment section.

TEXTUREVIEW: VIDEO CROPPING – FULL SCREEN VIDEO BACKGROUND IN ANDROID APPLICATIONS

Video Cropping

In this part of Android SurfaceView story we are going to create application which will do the following:

  • display video from assets folder using TextureView.
  • display a full screen background video without distorting the video size

This tutorial is derived from the creation of our latest app, TrackBack – available on the play store soon. Some XML names and items have been changed slightly to suite this tutorial. We used royalty free video and a basic video editor to adjust the video size and combine clips.

Final Results:

Step 1 – Preparing

Create Android project and target Android version 4.0. Make sure you have following lines in your AndroidManifest.xml file.

<uses-sdk
    android:minSdkVersion="14"
    android:targetSdkVersion="14"/>

Step 2 – XML

Copy a video file to your assets folder at res/raw. If raw doesn’t exist, make it.

In your values folder create dimen.xml file and add following lines.

<!-- common settings -->
<dimen name="padding_left_right">23dp</dimen>
<dimen name="margin_left_right">23dp</dimen>
<dimen name="margin_left_right_large">50dp</dimen>
<dimen name="margin_top_bottom">30dp</dimen>
<dimen name="margin_top_bottom_lg">90dp</dimen>
<dimen name="margin_btn_lg">50dp</dimen>
<dimen name="text_btn_lg">21dp</dimen>
<dimen name="margin_top_bottom_alt">45dp</dimen>
<dimen name="heading_lg">35sp</dimen>
<dimen name="heading_md">21sp</dimen>

In your values folder create string.xml file and add following lines – adjusting appropriately.

<!-- app required strings -->
<string name="app_name">TrackBack</string>
<!-- Strings related to login -->
<string name="welcome_login">Do you have an account? Sign in</string>
<string name="welcome_msg">Keep track of everyone and everything you love... in real time!</string>

In your layout folder create activity_video_crop.xml file or any appropriate name for this in your app.. and add following lines:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/welcome_constraint"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Activity_Welcome">

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

    <TextureView
        android:id="@+id/videoview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_gravity="center"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"

        >
    </TextureView>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/colorPrimarySeeThrough"
        >
    <ImageView
        android:layout_width="55dp"
        android:layout_height="55dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:layout_marginTop="@dimen/margin_top_bottom_lg"
        android:id="@+id/welcome_logo"
        android:src="@drawable/logo_white"
        />
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/margin_left_right"
            android:id="@+id/welcome_text"
          app:layout_constraintTop_toBottomOf="@+id/welcome_logo"
            android:text="@string/app_name"
            android:textSize="@dimen/heading_lg"
            android:textColor="@color/white"
            android:textStyle="bold"
            android:textAlignment="center"
            />
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="90dp"
            android:layout_marginRight="@dimen/margin_left_right"
            android:layout_marginLeft="@dimen/margin_left_right"
            android:id="@+id/welcome_note_2"
          app:layout_constraintBottom_toBottomOf="@+id/btn_start"
            android:text="@string/welcome_msg"
            android:textSize="@dimen/heading_md"
            android:textColor="@color/white"
            android:backgroundTint="@color/white"
            android:textAlignment="center"
            />
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
           android:background="@drawable/rounded_top_bottom_blue"
            android:text=" Continue "
            android:textSize="@dimen/text_btn_lg"
            android:textAlignment="center"
            android:gravity="center"
            android:foregroundGravity="center"
            android:textColor="@color/slight_white"
     app:layout_constraintBottom_toBottomOf="@id/welcome_sign_in"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
       android:layout_marginBottom="@dimen/margin_top_bottom_alt"
            android:layout_marginLeft="@dimen/margin_btn_lg"
            android:layout_marginRight="@dimen/margin_btn_lg"
            android:id="@+id/btn_start"
            />
        <TextView
            android:id="@+id/welcome_sign_in"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            android:textSize="20dp"
            android:textColor="@color/slight_white"
            android:text="@string/welcome_login"
        android:layout_marginBottom="@dimen/margin_top_bottom_lg"
            />
    </androidx.constraintlayout.widget.ConstraintLayout>
    </FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

Note: All that’s required here is the FrameLayout and the TextureView. I prefer using ConstraintLayout as the root to easily position items.

Step 3 – Basic code

Create a new activity class and call it ActivityCrop or something appropriate. Don’t forget to declare it inside AndroidManifest.xml file.

Imports:

package com.rahaprogramming.trackback;

import android.content.Context;
import android.graphics.Matrix;
import android.graphics.SurfaceTexture;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Surface;
import android.view.TextureView;
import android.widget.FrameLayout;
import androidx.appcompat.app.AppCompatActivity;
public class Activity_Welcome extends AppCompatActivity implements
        TextureView.SurfaceTextureListener, MediaPlayer.OnCompletionListener {
    //declare class variables
    Context context = this;
    Uri video_uri;
    
    // MediaPlayer instance
    private MediaPlayer mMediaPlayer;
    //views
    private TextureView mTextureView;
    FrameLayout frameLayout;
    Surface surface;
    // Original video size - we created this video and knew the size.
    // for unknown size - use meta data
    private float mVideoWidth = 1080;
    private float mVideoHeight = 1440;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_welcome);
        //Toolbar toolbar = findViewById(R.id.toolbar);
        //setSupportActionBar(toolbar);
        video_uri = Uri.parse("android.resource://"+getPackageName()+"/"+R.raw.trackback);

        //set views
        mTextureView = findViewById(R.id.videoview);
        mTextureView.setClickable(false);
        frameLayout = findViewById(R.id.welcome_frame);

        //init MediaPlayer
        mMediaPlayer = new MediaPlayer();

        //set implemented listeners
        mMediaPlayer.setOnCompletionListener(this);
        mTextureView.setSurfaceTextureListener(this);
    }
    //plays the video
    private void playVideo() {
        //its a big file - use separate thread
        new Thread(new Runnable() {
            public void run() {
                try {
                    mMediaPlayer.setDataSource(context,video_uri);
                    mMediaPlayer.setLooping(true);
                    mMediaPlayer.prepareAsync();
                    // Play video when the media source is ready for playback.
                    mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                        @Override
                        public void onPrepared(MediaPlayer mediaPlayer) {
                            mediaPlayer.start();
                        }
                    });
                } catch (Exception e) { // I can split the exceptions to get which error i need.
                    Utils.log("Error: "+e.toString());
                    e.printStackTrace();
                }
            }
        }).start();
    }
    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
        //set surface
        surface = new Surface(surfaceTexture);
        mMediaPlayer.setSurface(surface);
        //update viewable area
        updateTextureViewSize(width, height);
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) {
        //set surface
        surface = new Surface(surfaceTexture);
        mMediaPlayer.setSurface(surface);
        //update viewable area
        updateTextureViewSize(width, height);
    }

    //uses the view width to determine best crop to fit the screen
    //@param int viewWidth width of viewport
    //@param int viewHeight height of viewport
    private void updateTextureViewSize(int viewWidth, int viewHeight) {
        float scaleX = 1.0f;
        float scaleY = 1.0f;

        Utils.log(viewWidth+" "+viewHeight+" "+mVideoHeight+" "+mVideoWidth);
        if (mVideoWidth > viewWidth && mVideoHeight > viewHeight) {
            scaleX = mVideoWidth / viewWidth;
            scaleY = mVideoHeight / viewHeight;
        } else if (mVideoWidth < viewWidth && mVideoHeight < viewHeight) {
            scaleY = viewWidth / mVideoWidth;
            scaleX = viewHeight / mVideoHeight;
        } else if (viewWidth > mVideoWidth) {
            scaleY = (viewWidth / mVideoWidth) / (viewHeight / mVideoHeight);
        } else if (viewHeight > mVideoHeight) {
            scaleX = (viewHeight / mVideoHeight) / (viewWidth / mVideoWidth);
        }

        // Calculate pivot points, in our case crop from center
        int pivotPointX = viewWidth / 2;
        int pivotPointY = viewHeight / 2;

        Matrix matrix = new Matrix();
        matrix.setScale(scaleX, scaleY, pivotPointX, pivotPointY);
        //transform the video viewing size
        mTextureView.setTransform(matrix);
        //set the width and height of playing view
        mTextureView.setLayoutParams(new FrameLayout.LayoutParams(viewWidth, viewHeight));
        //finally, play the video
        playVideo();
    }

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

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {

    }

    // callback when the video is over
    public void onCompletion(MediaPlayer mp) {
        //if this happens.. never will.. just restart the video
        mp.stop();
        mp.release();
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mMediaPlayer != null) {
            // Make sure we stop video and release resources when activity is destroyed.
            mMediaPlayer.stop();
            mMediaPlayer.release();
            mMediaPlayer = null;
        }
    }
}

Step 5 – Video cropping

The resizing is done by the updateTextureViewSize method. First we need to calculate scaleX and scaleY factor and set it to Matrix object using method setScale(..). Next pass this matrix to TextureView by setTransform(..) method and you are done.

//uses the view width to determine best crop to fit the screen
    //@param int viewWidth width of viewport
    //@param int viewHeight height of viewport
    private void updateTextureViewSize(int viewWidth, int viewHeight) {
        float scaleX = 1.0f;
        float scaleY = 1.0f;

        Utils.log(viewWidth+" "+viewHeight+" "+mVideoHeight+" "+mVideoWidth);
        if (mVideoWidth > viewWidth && mVideoHeight > viewHeight) {
            scaleX = mVideoWidth / viewWidth;
            scaleY = mVideoHeight / viewHeight;
        } else if (mVideoWidth < viewWidth && mVideoHeight < viewHeight) {
            scaleY = viewWidth / mVideoWidth;
            scaleX = viewHeight / mVideoHeight;
        } else if (viewWidth > mVideoWidth) {
            scaleY = (viewWidth / mVideoWidth) / (viewHeight / mVideoHeight);
        } else if (viewHeight > mVideoHeight) {
            scaleX = (viewHeight / mVideoHeight) / (viewWidth / mVideoWidth);
        }

        // Calculate pivot points, in our case crop from center
        int pivotPointX = viewWidth / 2;
        int pivotPointY = viewHeight / 2;

        Matrix matrix = new Matrix();
        matrix.setScale(scaleX, scaleY, pivotPointX, pivotPointY);
        //transform the video viewing size
        mTextureView.setTransform(matrix);
        //set the width and height of playing view
        mTextureView.setLayoutParams(new FrameLayout.LayoutParams(viewWidth, viewHeight));
        //finally, play the video
        playVideo();
    }

Step 6 – Launch

When you launch application, you should notice that video is cropped correctly and displayed properly now. Of course, when width to height ratio is too big, video looses it quality as is scaled too much – as inImageView.setScaleType(ImageVIew.ScaleType.CENTER_CROP);