com.example.kuassivi.material_avatar.feature.ChooseAvatarActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.example.kuassivi.material_avatar.feature.ChooseAvatarActivity.java

Source

/*
 * Copyright (C) 2015 Francisco Gonzalez-Armijo Ridigos
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.example.kuassivi.material_avatar.feature;

import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.ActivityOptionsCompat;
import android.support.v4.view.ViewCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.transition.Transition;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;

import com.example.kuassivi.material_avatar.core.adapter.MarginDecoration;
import com.example.kuassivi.material_avatar.core.adapter.RecyclerViewAdapter;
import com.example.kuassivi.material_avatar.core.animation.CircleTransform;
import com.example.kuassivi.material_avatar.core.animation.ScalableBitmapAnimator;
import com.example.kuassivi.material_avatar.core.animation.TargetAdapter;
import com.example.kuassivi.material_avatar.core.model.ViewModel;
import com.example.kuassivi.material_avatar.core.transition.TransitionListenerAdapter;
import com.example.kuassivi.material_avatar.core.view.GalleryView;
import com.example.kuassivi.material_avatar.R;
import com.squareup.picasso.Picasso;

import java.util.ArrayList;
import java.util.List;

public class ChooseAvatarActivity extends AppCompatActivity
        implements RecyclerViewAdapter.OnItemClickListener, View.OnClickListener {

    /**
     * List of online avatars
     */
    private static List<ViewModel> items = new ArrayList<>();
    static {
        for (int i = 1; i <= 10; i++) {
            items.add(new ViewModel("http://lorempixel.com/500/500/people/" + i));
        }
    }

    /**
     * Shared view (biggest component)
     */
    private ImageButton mSharedAvatarView;

    /**
     * Our header view, where the shared view will appear
     */
    private FrameLayout mHeaderView;

    /**
     * A custom ImageView that will use the ScalableBitmapAnimator class to flash and scale down effect
     */
    private GalleryView mAvatarContainer;

    /**
     * The Fab button to apply selected avatar and return to ProfileActivity
     */
    private FloatingActionButton mFabView;

    /**
     * The size of the new shared view
     */
    private int sharedAvatarSize;

    /**
     * Variable used to store and deliver the selected avatar to ProfileActivity
     */
    private String mAvatarUrl;

    /**
     * Navigate to this Activity
     * <br>Start activity with material transition
     * <br>We use startActivityForResult() method to be able to deliver the chosen avatar on ProfileActivity
     *
     * @param context Activity
     * @param transitionView View
     * @param savedAvatarUrl String
     */
    public static void navigate(Activity context, View transitionView, String savedAvatarUrl) {
        Intent intent = new Intent(context, ChooseAvatarActivity.class);
        intent.putExtra(ProfileActivity.Extra.AVATAR_URL, savedAvatarUrl);

        ActivityOptionsCompat optionsCompat = ActivityOptionsCompat.makeSceneTransitionAnimation(context,
                transitionView, context.getString(R.string.transition_name));
        ActivityCompat.startActivityForResult(context, intent, ProfileActivity.REQUEST_AVATAR_SELECTION_CODE,
                optionsCompat.toBundle());
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Postpone any pending transition before image url are loaded from Picasso
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            postponeEnterTransition();
            initTransitions();
        }

        setContentView(R.layout.activity_choose_avatar);

        // Setup views and adapter, then start postponed transitions once Picasso has loaded image
        setupViews();
        setupAdapter();

        if (savedInstanceState != null) {
            mAvatarUrl = savedInstanceState.getString(ProfileActivity.Extra.AVATAR_URL);
            showFabView();
        }

        updateAvatarAndStartTransition();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putString(ProfileActivity.Extra.AVATAR_URL, mAvatarUrl);
        super.onSaveInstanceState(outState);
    }

    private void setupViews() {
        sharedAvatarSize = getResources().getDimensionPixelSize(R.dimen.avatar_size_expanded);

        mAvatarUrl = getIntent().getStringExtra(ProfileActivity.Extra.AVATAR_URL);

        mSharedAvatarView = (ImageButton) findViewById(R.id.shared_avatar_view);
        mHeaderView = (FrameLayout) findViewById(R.id.header_view);
        mAvatarContainer = (GalleryView) mHeaderView.findViewById(R.id.avatar_container);
        mFabView = (FloatingActionButton) findViewById(R.id.fab);
        mFabView.setVisibility(View.GONE);
        mFabView.setOnClickListener(this);
    }

    private void setupAdapter() {
        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        recyclerView.addItemDecoration(new MarginDecoration(this));
        recyclerView.setHasFixedSize(true);
        RecyclerViewAdapter adapter = new RecyclerViewAdapter(items);
        adapter.setOnItemClickListener(this);
        //        adapter.setAnimationStartAfter(
        //                getResources().getInteger(R.integer.curve_motion_delay) * 2);
        recyclerView.setAdapter(adapter);
    }

    /**
     * If there is no a previous avatar loaded, then just start material transitions
     */
    private void updateAvatarAndStartTransition() {
        if (mAvatarUrl != null) {
            Picasso.with(this).load(mAvatarUrl).into(new TargetAdapter() {
                @Override
                public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {

                    updateSharedAvatarView(bitmap);

                    mAvatarContainer.setImageBitmap(bitmap);
                    mAvatarContainer.setScaleType(ImageView.ScaleType.CENTER_CROP);

                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                        startPostponedEnterTransition();
                    }
                }
            });
        } else {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                startPostponedEnterTransition();
            }
        }
    }

    @Override
    public void onItemClick(View view, final ViewModel viewModel) {
        // Save the current image url, as our chosen avatar
        mAvatarUrl = viewModel.getImage();
        // Load the image, and then perform some cool animations on it
        Picasso.with(this).load(viewModel.getImage()).into(new TargetAdapter() {
            @Override
            public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {

                updateSharedAvatarView(bitmap);

                /*
                 * Scale down from a bigger image size
                 * And flash it at its first shown
                 */
                long duration = getResources().getInteger(R.integer.bitmap_motion);
                ScalableBitmapAnimator bitmapAnimator = new ScalableBitmapAnimator(
                        ScalableBitmapAnimator.SCALE_FROM);
                bitmapAnimator.setDuration(duration).setInterpolator(new DecelerateInterpolator());
                mAvatarContainer.setImageBitmap(bitmap, true).setBitmapAnimators(bitmapAnimator)
                        .startBitmapAnimation();

            }
        });

        // Once we have chosen at least one avatar, show the fab view to apply the selected choice
        showFabView();
    }

    private void showFabView() {
        // Show only once
        if (mFabView.getVisibility() == View.GONE) {
            ViewCompat.setAlpha(mFabView, 0);
            mFabView.setVisibility(View.VISIBLE);
            mFabView.post(new Runnable() {
                @Override
                public void run() {
                    ViewCompat.setTranslationX(mFabView, mFabView.getMeasuredWidth());
                    ViewCompat.animate(mFabView).translationX(0).alpha(1).start();
                }
            });
        }
    }

    /**
     * This method updates the shared view we use on the material transition
     *
     * @param bitmap Bitmap
     */
    private void updateSharedAvatarView(Bitmap bitmap) {
        Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, sharedAvatarSize, sharedAvatarSize, true);
        CircleTransform circleTransform = new CircleTransform();
        mSharedAvatarView
                .setBackground(new BitmapDrawable(getResources(), circleTransform.transform(scaledBitmap)));
    }

    /**
     * This method will not fire on devices prior to LOLLIPOP
     */
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private void initTransitions() {
        // Perform some visibility strategies on the header and shared views
        getWindow().getSharedElementEnterTransition().addListener(new TransitionListenerAdapter() {
            @Override
            public void onTransitionStart(Transition transition) {
                mHeaderView.setVisibility(View.INVISIBLE);
            }

            @Override
            public void onTransitionEnd(Transition transition) {
                mHeaderView.setVisibility(View.VISIBLE);
                mSharedAvatarView.setAlpha(0f);
            }
        });

        // Setup the return transition
        getWindow().getReturnTransition().addListener(new TransitionListenerAdapter() {
            @Override
            public void onTransitionStart(Transition transition) {

                final long duration = getResources().getInteger(R.integer.duration_fast);

                if (mAvatarUrl != null) {
                    int dWidth = mAvatarContainer.getDrawableWidth(),
                            dHeight = mAvatarContainer.getDrawableHeight(),
                            vWidth = mAvatarContainer.getInsetWidth(), vHeight = mAvatarContainer.getInsetHeight();

                    float scaleTo = (float) sharedAvatarSize / (float) vHeight;
                    long delay = Float
                            .valueOf((float) duration
                                    / (((float) vWidth / (float) vHeight) + ((float) dWidth / (float) dHeight)))
                            .longValue();

                    ScalableBitmapAnimator bitmapAnimator = new ScalableBitmapAnimator(scaleTo,
                            ScalableBitmapAnimator.SCALE_TO);
                    bitmapAnimator.setScaleFactor(1f).setInterpolator(new DecelerateInterpolator())
                            .setDuration(duration).setStartDelay(delay);
                    mAvatarContainer.setBitmapAnimators(bitmapAnimator).startBitmapAnimation();
                }

                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        if (mSharedAvatarView != null && !isFinishing()) {
                            mSharedAvatarView.setAlpha(1f);
                        }
                    }
                }, duration);
            }
        });
    }

    /**
     * When the Fab view is tapped, deliver the image url saved on ProfileActivity
     *
     * @param v View
     */
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.fab:
            Intent returnIntent = new Intent();
            returnIntent.putExtra(ProfileActivity.Extra.AVATAR_URL, mAvatarUrl);
            setResult(RESULT_OK, returnIntent);
            supportFinishAfterTransition();
            ViewCompat.animate(v).translationX(v.getMeasuredWidth()).start();
            break;
        }
    }
}