/* * Copyright 2014 Soichiro Kashima * * 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.marshalchen.common.demoofui.observablescrollview; import android.content.res.TypedArray; import android.graphics.Color; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.support.v7.widget.Toolbar; import android.util.TypedValue; import android.view.View; import android.widget.AbsListView; import android.widget.ArrayAdapter; import android.widget.TextView; import com.github.ksoichiro.android.observablescrollview.ObservableListView; import com.github.ksoichiro.android.observablescrollview.ObservableScrollViewCallbacks; import com.github.ksoichiro.android.observablescrollview.ScrollState; import com.marshalchen.common.demoofui.R; import com.nineoldandroids.view.ViewHelper; import com.nineoldandroids.view.ViewPropertyAnimator; import java.util.ArrayList; import java.util.List; public class FlexibleSpaceWithImageListViewActivity extends ActionBarActivity implements ObservableScrollViewCallbacks { private static final float MAX_TEXT_SCALE_DELTA = 0.3f; private static final boolean TOOLBAR_IS_STICKY = false; private View mToolbar; private View mImageView; private View mOverlayView; private View mListBackgroundView; private TextView mTitleView; private View mFab; private int mActionBarSize; private int mFlexibleSpaceShowFabOffset; private int mFlexibleSpaceImageHeight; private int mFabMargin; private int mToolbarColor; private boolean mFabIsShown; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.observable_scroll_view_activity_flexiblespacewithimagelistview); setSupportActionBar((Toolbar) findViewById(R.id.toolbar)); mFlexibleSpaceImageHeight = getResources().getDimensionPixelSize(R.dimen.flexible_space_image_height); mFlexibleSpaceShowFabOffset = getResources().getDimensionPixelSize(R.dimen.flexible_space_show_fab_offset); mActionBarSize = getActionBarSize(); mToolbarColor = getResources().getColor(R.color.primary); mToolbar = findViewById(R.id.toolbar); if (!TOOLBAR_IS_STICKY) { mToolbar.setBackgroundColor(Color.TRANSPARENT); } mImageView = findViewById(R.id.image); mOverlayView = findViewById(R.id.overlay); ObservableListView listView = (ObservableListView) findViewById(R.id.list); listView.setScrollViewCallbacks(this); // Set padding view for ListView. This is the flexible space. View paddingView = new View(this); AbsListView.LayoutParams lp = new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT, mFlexibleSpaceImageHeight); paddingView.setLayoutParams(lp); // This is required to disable header's list selector effect paddingView.setClickable(true); listView.addHeaderView(paddingView); List<String> items = new ArrayList<String>(); for (int i = 1; i <= 100; i++) { items.add("Item " + i); } listView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, items)); mTitleView = (TextView) findViewById(R.id.title); mTitleView.setText(getTitle()); setTitle(null); mFab = findViewById(R.id.fab); mFabMargin = getResources().getDimensionPixelSize(R.dimen.margin_standard); ViewHelper.setScaleX(mFab, 0); ViewHelper.setScaleY(mFab, 0); // mListBackgroundView makes ListView's background except header view. mListBackgroundView = findViewById(R.id.list_background); final View contentView = getWindow().getDecorView().findViewById(android.R.id.content); contentView.post(new Runnable() { @Override public void run() { // mListBackgroundView's should fill its parent vertically // but the height of the content view is 0 on 'onCreate'. // So we should get it with post(). mListBackgroundView.getLayoutParams().height = contentView.getHeight(); } }); } @Override public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) { // Translate overlay and image float flexibleRange = mFlexibleSpaceImageHeight - mActionBarSize; int minOverlayTransitionY = mActionBarSize - mOverlayView.getHeight(); ViewHelper.setTranslationY(mOverlayView, Math.max(minOverlayTransitionY, Math.min(0, -scrollY))); ViewHelper.setTranslationY(mImageView, Math.max(minOverlayTransitionY, Math.min(0, -scrollY / 2))); // Translate list background ViewHelper.setTranslationY(mListBackgroundView, Math.max(0, -scrollY + mFlexibleSpaceImageHeight)); // Change alpha of overlay ViewHelper.setAlpha(mOverlayView, Math.max(0, Math.min(1, (float) scrollY / flexibleRange))); // Scale title text float scale = 1 + Math.max(0, Math.min(MAX_TEXT_SCALE_DELTA, (flexibleRange - scrollY) / flexibleRange)); ViewHelper.setPivotX(mTitleView, 0); ViewHelper.setPivotY(mTitleView, 0); ViewHelper.setScaleX(mTitleView, scale); ViewHelper.setScaleY(mTitleView, scale); // Translate title text int maxTitleTranslationY = (int) (mFlexibleSpaceImageHeight - mTitleView.getHeight() * scale); int titleTranslationY = maxTitleTranslationY - scrollY; if (TOOLBAR_IS_STICKY) { titleTranslationY = Math.max(0, titleTranslationY); } ViewHelper.setTranslationY(mTitleView, titleTranslationY); // Translate FAB int maxFabTranslationY = mFlexibleSpaceImageHeight - mFab.getHeight() / 2; int fabTranslationY = Math.max(mActionBarSize - mFab.getHeight() / 2, Math.min(maxFabTranslationY, -scrollY + mFlexibleSpaceImageHeight - mFab.getHeight() / 2)); ViewHelper.setTranslationX(mFab, mOverlayView.getWidth() - mFabMargin - mFab.getWidth()); ViewHelper.setTranslationY(mFab, fabTranslationY); // Show/hide FAB if (ViewHelper.getTranslationY(mFab) < mFlexibleSpaceShowFabOffset) { hideFab(); } else { showFab(); } if (TOOLBAR_IS_STICKY) { // Change alpha of toolbar background if (-scrollY + mFlexibleSpaceImageHeight <= mActionBarSize) { setBackgroundAlpha(mToolbar, 1, mToolbarColor); } else { setBackgroundAlpha(mToolbar, 0, mToolbarColor); } } else { // Translate Toolbar if (scrollY < mFlexibleSpaceImageHeight) { ViewHelper.setTranslationY(mToolbar, 0); } else { ViewHelper.setTranslationY(mToolbar, -scrollY); } } } @Override public void onDownMotionEvent() { } @Override public void onUpOrCancelMotionEvent(ScrollState scrollState) { } private int getActionBarSize() { TypedValue typedValue = new TypedValue(); int[] textSizeAttr = new int[]{R.attr.actionBarSize}; int indexOfAttrTextSize = 0; TypedArray a = obtainStyledAttributes(typedValue.data, textSizeAttr); int actionBarSize = a.getDimensionPixelSize(indexOfAttrTextSize, -1); a.recycle(); return actionBarSize; } private void showFab() { if (!mFabIsShown) { ViewPropertyAnimator.animate(mFab).cancel(); ViewPropertyAnimator.animate(mFab).scaleX(1).scaleY(1).setDuration(200).start(); mFabIsShown = true; } } private void hideFab() { if (mFabIsShown) { ViewPropertyAnimator.animate(mFab).cancel(); ViewPropertyAnimator.animate(mFab).scaleX(0).scaleY(0).setDuration(200).start(); mFabIsShown = false; } } private void setBackgroundAlpha(View view, float alpha, int baseColor) { int a = Math.min(255, Math.max(0, (int) (alpha * 255))) << 24; int rgb = 0x00ffffff & baseColor; view.setBackgroundColor(a + rgb); } }