Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(20)

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/contextmenu/TabularContextMenuViewPager.java

Issue 2960743002: Adding animations for view pager transitions (Closed)
Patch Set: moving animator call Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/android/java/res/layout/tabular_context_menu.xml ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.chrome.browser.contextmenu; 5 package org.chromium.chrome.browser.contextmenu;
6 6
7 import android.animation.Animator;
8 import android.animation.AnimatorListenerAdapter;
9 import android.animation.ValueAnimator;
10 import android.animation.ValueAnimator.AnimatorUpdateListener;
7 import android.content.Context; 11 import android.content.Context;
12 import android.graphics.Canvas;
13 import android.graphics.drawable.Drawable;
8 import android.support.v4.view.ViewPager; 14 import android.support.v4.view.ViewPager;
15 import android.support.v4.view.animation.LinearOutSlowInInterpolator;
9 import android.util.AttributeSet; 16 import android.util.AttributeSet;
10 import android.view.View; 17 import android.view.View;
11 18
19 import org.chromium.base.ApiCompatibilityUtils;
12 import org.chromium.chrome.R; 20 import org.chromium.chrome.R;
13 21
14 /** 22 /**
15 * When there is more than one view for the context menu to display, it wraps th e display in a view 23 * When there is more than one view for the context menu to display, it wraps th e display in a view
16 * pager. 24 * pager.
17 */ 25 */
18 public class TabularContextMenuViewPager extends ViewPager { 26 public class TabularContextMenuViewPager extends ViewPager {
27 private static final int ANIMATION_DURATION_MS = 250;
28
29 private ValueAnimator mAnimator;
30 private int mOldHeight;
31 private int mCanvasWidth;
32 private int mClipHeight;
33
34 private int mDifferenceInHeight = 0;
Ted C 2017/07/20 22:00:55 0 is the default value in java, so you don't need
Daniel Park 2017/07/20 22:19:38 Done.
35 private int mPreviousChildIndex = 1;
19 private final int mContextMenuMinimumPaddingPx = 36 private final int mContextMenuMinimumPaddingPx =
Ted C 2017/07/20 22:00:55 nit, but put the finals above non-finals
Daniel Park 2017/07/20 22:19:37 Done.
20 getResources().getDimensionPixelSize(R.dimen.context_menu_min_paddin g); 37 getResources().getDimensionPixelSize(R.dimen.context_menu_min_paddin g);
38 private final Drawable mDrawable = ApiCompatibilityUtils.getDrawable(
Ted C 2017/07/20 22:00:55 Let's call this something like mBackgroundDrawable
Daniel Park 2017/07/20 22:19:38 Done.
39 getResources(), R.drawable.white_with_rounded_corners);
21 40
22 public TabularContextMenuViewPager(Context context) { 41 public TabularContextMenuViewPager(Context context) {
Ted C 2017/07/20 22:00:55 I think you should be able to delete this construc
Daniel Park 2017/07/20 22:19:38 Done.
23 super(context); 42 super(context);
43 mDrawable.mutate();
24 } 44 }
25 45
26 public TabularContextMenuViewPager(Context context, AttributeSet attrs) { 46 public TabularContextMenuViewPager(Context context, AttributeSet attrs) {
27 super(context, attrs); 47 super(context, attrs);
48 mDrawable.mutate();
28 } 49 }
29 50
30 /** 51 /**
31 * Used to show the full ViewPager dialog. Without this the dialog would hav e no height or 52 * Used to show the full ViewPager dialog. Without this the dialog would hav e no height or
32 * width. 53 * width.
33 */ 54 */
34 @Override 55 @Override
35 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 56 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
57 int tabHeight = 0;
36 int menuHeight = 0; 58 int menuHeight = 0;
37 int tabHeight = 0;
38
39 // getCurrentItem() does not take into account the tab layout unlike get ChildCount().
40 int currentItemsIndex = getCurrentItem() + 1;
41 59
42 // The width of the context menu is defined so that it leaves space betw een itself and the 60 // The width of the context menu is defined so that it leaves space betw een itself and the
43 // screen's edges. It is also bounded to a max size to prevent the menu from stretching 61 // screen's edges. It is also bounded to a max size to prevent the menu from stretching
44 // across a large display (e.g. a tablet screen). 62 // across a large display (e.g. a tablet screen).
45 int deviceWidthPx = getResources().getDisplayMetrics().widthPixels; 63 int appWindowWidthPx = getResources().getDisplayMetrics().widthPixels;
46 int contextMenuWidth = Math.min(deviceWidthPx - 2 * mContextMenuMinimumP addingPx, 64 int contextMenuWidth = Math.min(appWindowWidthPx - 2 * mContextMenuMinim umPaddingPx,
47 getResources().getDimensionPixelSize(R.dimen.context_menu_max_wi dth)); 65 getResources().getDimensionPixelSize(R.dimen.context_menu_max_wi dth));
48 66
49 widthMeasureSpec = MeasureSpec.makeMeasureSpec(contextMenuWidth, Measure Spec.EXACTLY); 67 widthMeasureSpec = MeasureSpec.makeMeasureSpec(contextMenuWidth, Measure Spec.EXACTLY);
50 68
51 // The height of the context menu is calculated as the sum of: 69 // getCurrentItem() returns the index of the current page in the pager's pages.
52 // 1. The tab bar's height, which is only visible when the context menu requires it 70 // It does not take into account the tab layout like getChildCount(), so we add 1.
53 // (i.e. an ImageLink is clicked) 71 int currentChildIndex = getCurrentItem() + 1;
54 // 2. The height of the View being displayed for the current tab.
55 for (int i = 0; i < getChildCount(); i++) {
56 View child = getChildAt(i);
57 72
58 child.measure( 73 // Handles the case where this is called while the pager is scrolling be tween views.
59 widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec .UNSPECIFIED)); 74 // The height should remain the same as the height of the last view seen before scrolling.
60 int measuredHeight = child.getMeasuredHeight(); 75 if (getScrollX() != 0 && getScrollX() != mCanvasWidth) {
76 heightMeasureSpec = MeasureSpec.makeMeasureSpec(mOldHeight, MeasureS pec.EXACTLY);
77 } else {
78 // The height of the context menu is calculated as the sum of:
79 // 1. The tab bar's height, which is only visible when the context m enu requires it
80 // (i.e. an ImageLink is clicked)
81 // 2. The height of the View being displayed for the current tab.
82 for (int i = 0; i < getChildCount(); i++) {
83 View child = getChildAt(i);
84 child.measure(
85 widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, Measure Spec.UNSPECIFIED));
86 int measuredHeight = child.getMeasuredHeight();
61 87
62 // The ViewPager also considers the tab layout one of its children, and needs to be 88 // The ViewPager also considers the tab layout one of its childr en, and needs to be
63 // treated separately from getting the largest height. 89 // treated separately from getting the largest height.
64 if (child.getId() == R.id.tab_layout && child.getVisibility() != GON E) { 90 if (child.getId() == R.id.tab_layout && child.getVisibility() != GONE) {
65 tabHeight = measuredHeight; 91 tabHeight = measuredHeight;
66 } else if (i == currentItemsIndex) { 92 } else if (i == currentChildIndex) {
67 menuHeight = child.getMeasuredHeight(); 93 menuHeight = child.getMeasuredHeight();
68 break; 94 break;
95 }
96 }
97 int fullHeight = menuHeight + tabHeight;
98 int appWindowHeightPx = getResources().getDisplayMetrics().heightPix els;
99 fullHeight = Math.min(fullHeight, appWindowHeightPx - 2 * mContextMe nuMinimumPaddingPx);
100 mDifferenceInHeight = fullHeight - mOldHeight;
101
102 if (currentChildIndex == mPreviousChildIndex) {
103 // Handles the snapping of the view when its height changes
104 // (i.e. an image finished loading or the link became fully visi ble).
105 // The pager will immediately snap to the new height.
106 mClipHeight = fullHeight;
107 if (menuHeight != 0) mOldHeight = fullHeight;
108 heightMeasureSpec = MeasureSpec.makeMeasureSpec(fullHeight, Meas ureSpec.EXACTLY);
109 } else {
110 // Handles the case where the view pager has completely scrolled to a different
111 // child. It will measure to the larger height so the clipping i s visible.
112 initAnimator();
113 heightMeasureSpec = MeasureSpec.makeMeasureSpec(
114 Math.max(mOldHeight, fullHeight), MeasureSpec.EXACTLY);
69 } 115 }
70 } 116 }
117 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
118 mPreviousChildIndex = currentChildIndex;
119 // The animation is only visible when switching to a tab with a differen t height.
Theresa 2017/07/20 21:54:58 nit: s/visible/run
Daniel Park 2017/07/20 22:19:38 Done.
120 if (mAnimator != null) mAnimator.start();
121 }
71 122
72 // Cap the height of the context menu so that it fits on the screen with out touching the 123 private void initAnimator() {
73 // screen's edges. 124 if (mAnimator != null) return;
74 int fullHeight = menuHeight + tabHeight; 125 mAnimator = ValueAnimator.ofFloat(0f, 1f);
75 int deviceHeightPx = getResources().getDisplayMetrics().heightPixels; 126 mAnimator.setDuration(ANIMATION_DURATION_MS);
76 fullHeight = Math.min(fullHeight, deviceHeightPx - 2 * mContextMenuMinim umPaddingPx); 127 mAnimator.setInterpolator(new LinearOutSlowInInterpolator());
128 mAnimator.addUpdateListener(new AnimatorUpdateListener() {
77 129
78 heightMeasureSpec = MeasureSpec.makeMeasureSpec(fullHeight, MeasureSpec. EXACTLY); 130 @Override
79 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 131 public void onAnimationUpdate(ValueAnimator animation) {
132 float animatedValue = (float) animation.getAnimatedValue();
133 if (mDifferenceInHeight < 0) {
134 setTranslationY(animatedValue * -mDifferenceInHeight / 2);
135 } else {
136 setTranslationY((1 - animatedValue) * mDifferenceInHeight / 2);
137 }
138 mClipHeight = mOldHeight + (int) (mDifferenceInHeight * animated Value);
139 invalidate();
140 }
141 });
142 mAnimator.addListener(new AnimatorListenerAdapter() {
143 @Override
144 public void onAnimationEnd(Animator animation) {
145 mOldHeight = mClipHeight;
146 setTranslationY(0);
147 if (mDifferenceInHeight < 0) requestLayout();
148 }
149 });
150 }
151
152 @Override
153 public void onDraw(Canvas canvas) {
154 mCanvasWidth = canvas.getWidth();
155 int backgroundOffsetX = getScrollX();
156 mDrawable.setBounds(
157 backgroundOffsetX, 0, canvas.getWidth() + backgroundOffsetX, mCl ipHeight);
158 mDrawable.draw(canvas);
159
160 boolean clipped = false;
161 if (mClipHeight != 0) {
162 canvas.save();
163 canvas.clipRect(0, 0, mCanvasWidth, mClipHeight);
164 clipped = true;
165 }
166
167 super.onDraw(canvas);
168
169 if (clipped) {
170 canvas.restore();
171 }
80 } 172 }
81 } 173 }
OLDNEW
« no previous file with comments | « chrome/android/java/res/layout/tabular_context_menu.xml ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698