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

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: Add a todo 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.Animator.AnimatorListener;
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.Rect;
14 import android.graphics.drawable.Drawable;
15 import android.support.v4.view.ViewCompat;
8 import android.support.v4.view.ViewPager; 16 import android.support.v4.view.ViewPager;
17 import android.support.v4.view.animation.LinearOutSlowInInterpolator;
9 import android.util.AttributeSet; 18 import android.util.AttributeSet;
10 import android.view.View; 19 import android.view.View;
11 20
21 import org.chromium.base.ApiCompatibilityUtils;
12 import org.chromium.chrome.R; 22 import org.chromium.chrome.R;
23 import org.chromium.chrome.browser.util.MathUtils;
13 24
14 /** 25 /**
15 * When there is more than one view for the context menu to display, it wraps th e display in a view 26 * When there is more than one view for the context menu to display, it wraps th e display in a view
16 * pager. 27 * pager.
17 */ 28 */
18 public class TabularContextMenuViewPager extends ViewPager { 29 public class TabularContextMenuViewPager extends ViewPager {
30 private static final int ANIMATION_DURATION_MS = 250;
31
32 private ValueAnimator mAnimator;
33 private int mOldHeight;
34 private int mCanvasWidth;
35 private int mClipHeight;
36
37 private int mDifferenceInHeight = 0;
38 private int mPreviousChildIndex = 1;
19 private final int mContextMenuMinimumPaddingPx = 39 private final int mContextMenuMinimumPaddingPx =
20 getResources().getDimensionPixelSize(R.dimen.context_menu_min_paddin g); 40 getResources().getDimensionPixelSize(R.dimen.context_menu_min_paddin g);
21 41
22 public TabularContextMenuViewPager(Context context) { 42 public TabularContextMenuViewPager(Context context) {
23 super(context); 43 super(context);
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);
28 } 48 }
29 49
30 /** 50 /**
31 * Used to show the full ViewPager dialog. Without this the dialog would hav e no height or 51 * Used to show the full ViewPager dialog. Without this the dialog would hav e no height or
32 * width. 52 * width.
33 */ 53 */
34 @Override 54 @Override
35 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 55 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
56 int tabHeight = 0;
36 int menuHeight = 0; 57 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 58
42 // The width of the context menu is defined so that it leaves space betw een itself and the 59 // 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 60 // 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). 61 // across a large display (e.g. a tablet screen).
45 int deviceWidthPx = getResources().getDisplayMetrics().widthPixels; 62 int appWindowWidthPx = getResources().getDisplayMetrics().widthPixels;
46 int contextMenuWidth = Math.min(deviceWidthPx - 2 * mContextMenuMinimumP addingPx, 63 int contextMenuWidth = Math.min(appWindowWidthPx - 2 * mContextMenuMinim umPaddingPx,
47 getResources().getDimensionPixelSize(R.dimen.context_menu_max_wi dth)); 64 getResources().getDimensionPixelSize(R.dimen.context_menu_max_wi dth));
48 65
49 widthMeasureSpec = MeasureSpec.makeMeasureSpec(contextMenuWidth, Measure Spec.EXACTLY); 66 widthMeasureSpec = MeasureSpec.makeMeasureSpec(contextMenuWidth, Measure Spec.EXACTLY);
50 67
51 // The height of the context menu is calculated as the sum of: 68 // getCurrentItem() does not take into account the tab layout unlike get ChildCount().
52 // 1. The tab bar's height, which is only visible when the context menu requires it 69 int currentChildIndex = getCurrentItem() + 1;
53 // (i.e. an ImageLink is clicked)
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 70
58 child.measure( 71 // Handles the case where this is called while the pager is scrolling be tween views.
59 widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec .UNSPECIFIED)); 72 if (getScrollX() != 0 && getScrollX() != mCanvasWidth) {
60 int measuredHeight = child.getMeasuredHeight(); 73 heightMeasureSpec = MeasureSpec.makeMeasureSpec(mOldHeight, MeasureS pec.EXACTLY);
74 } else {
75 // The height of the context menu is calculated as the sum of:
76 // 1. The tab bar's height, which is only visible when the context m enu requires it
77 // (i.e. an ImageLink is clicked)
78 // 2. The height of the View being displayed for the current tab.
79 for (int i = 0; i < getChildCount(); i++) {
80 View child = getChildAt(i);
81 child.measure(
82 widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, Measure Spec.UNSPECIFIED));
83 int measuredHeight = child.getMeasuredHeight();
61 84
62 // The ViewPager also considers the tab layout one of its children, and needs to be 85 // The ViewPager also considers the tab layout one of its childr en, and needs to be
63 // treated separately from getting the largest height. 86 // treated separately from getting the largest height.
64 if (child.getId() == R.id.tab_layout && child.getVisibility() != GON E) { 87 if (child.getId() == R.id.tab_layout && child.getVisibility() != GONE) {
65 tabHeight = measuredHeight; 88 tabHeight = measuredHeight;
66 } else if (i == currentItemsIndex) { 89 } else if (i == currentChildIndex) {
67 menuHeight = child.getMeasuredHeight(); 90 menuHeight = child.getMeasuredHeight();
68 break; 91 break;
92 }
93 }
94 int fullHeight = menuHeight + tabHeight;
95 int appWindowHeightPx = getResources().getDisplayMetrics().heightPix els;
96 fullHeight = Math.min(fullHeight, appWindowHeightPx - 2 * mContextMe nuMinimumPaddingPx);
97 mDifferenceInHeight = fullHeight - mOldHeight;
98
99 if (currentChildIndex == mPreviousChildIndex) {
100 // Handles the snapping and re-clipping of the view when its hei ght changes
101 // (i.e. an image finished loading or the link became fully visi ble).
102 mClipHeight = fullHeight;
103 if (menuHeight != 0) mOldHeight = fullHeight;
104 heightMeasureSpec = MeasureSpec.makeMeasureSpec(fullHeight, Meas ureSpec.EXACTLY);
105 // Clip logic is not called on orientation changes, so it must b e set here.
106 setClipDimensionsForResize(contextMenuWidth);
107 } else {
108 // Handles the case where the view pager has completely scrolled to a different
109 // child.
110 if (mAnimator == null) initAnimator();
111 heightMeasureSpec = MeasureSpec.makeMeasureSpec(
112 Math.max(mOldHeight, fullHeight), MeasureSpec.EXACTLY);
113 mAnimator.start();
69 } 114 }
70 } 115 }
116 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
117 mPreviousChildIndex = currentChildIndex;
118 }
71 119
72 // Cap the height of the context menu so that it fits on the screen with out touching the 120 public void setClipDimensionsForResize(int width) {
73 // screen's edges. 121 // TODO(injae): Find a different way to mimic animations
Theresa 2017/07/17 21:28:25 I think we should address this TODO now, since it
Daniel Park 2017/07/19 00:30:09 Done.
74 int fullHeight = menuHeight + tabHeight; 122 ViewCompat.setClipBounds(this, new Rect(0, 0, width, mClipHeight));
75 int deviceHeightPx = getResources().getDisplayMetrics().heightPixels; 123 }
76 fullHeight = Math.min(fullHeight, deviceHeightPx - 2 * mContextMenuMinim umPaddingPx);
77 124
78 heightMeasureSpec = MeasureSpec.makeMeasureSpec(fullHeight, MeasureSpec. EXACTLY); 125 private void initAnimator() {
79 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 126 mAnimator = ValueAnimator.ofFloat(0f, 1f);
Ted C 2017/07/17 21:25:31 I would do: if (mAnimator != null && mAnimator.is
Daniel Park 2017/07/19 00:30:09 Done.
Theresa 2017/07/19 15:23:20 If the animator is running and another layout chan
Daniel Park 2017/07/19 20:26:44 The animation finishes and is laid out properly; n
127 mAnimator.setDuration(ANIMATION_DURATION_MS);
128 mAnimator.setInterpolator(new LinearOutSlowInInterpolator());
129 mAnimator.addUpdateListener(new AnimatorUpdateListener() {
130
131 @Override
132 public void onAnimationUpdate(ValueAnimator animation) {
133 float animatedValue = (float) animation.getAnimatedValue();
134 // If the animation duration is long enough (e.g. 5x, 10x), anim atedValue will
135 // undesirably be set to 1f more than once.
136 if (mDifferenceInHeight < 0) {
137 setTranslationY(animatedValue * -mDifferenceInHeight / 2);
138 } else {
139 setTranslationY((1 - animatedValue) * mDifferenceInHeight / 2);
140 }
141 mClipHeight = mOldHeight + (int) (mDifferenceInHeight * animated Value);
142 ViewCompat.setClipBounds(TabularContextMenuViewPager.this,
143 new Rect(0, 0, mCanvasWidth, mClipHeight));
144 invalidate();
145 if (MathUtils.areFloatsEqual(animatedValue, 1f)) {
146 return;
Theresa 2017/07/17 21:28:25 We're already at the end of the method so this ear
Daniel Park 2017/07/19 00:30:08 the animated value will hit 1 twice if the animati
Theresa 2017/07/19 15:23:20 My point is that nothing happens in this method af
Daniel Park 2017/07/19 20:26:44 Removed; the issue's not appearing anymore.
147 }
148 }
149 });
150 mAnimator.addListener(new AnimatorListener() {
Ted C 2017/07/17 21:25:31 take a look at CancelAwareAnimatorListener or Anim
Theresa 2017/07/17 21:28:25 You can use AnimatorListenerAdapter to avoid provi
Daniel Park 2017/07/19 00:30:08 Done.
151
152 @Override
153 public void onAnimationStart(Animator animation) {}
154
155 @Override
156 public void onAnimationRepeat(Animator animation) {}
157
158 @Override
159 public void onAnimationEnd(Animator animation) {
160 mOldHeight = mClipHeight;
161 requestLayout();
Ted C 2017/07/17 21:25:31 do we only need to request layout if the new heigh
Daniel Park 2017/07/19 00:30:08 Done.
162 setTranslationY(0);
Theresa 2017/07/17 21:28:25 nit: if you can flip setTranslationY(0) and reques
Daniel Park 2017/07/19 00:30:08 Done.
163 }
164
165 @Override
166 public void onAnimationCancel(Animator animation) {}
167 });
168 }
169
170 @Override
171 public void onDraw(Canvas canvas) {
172 mCanvasWidth = canvas.getWidth();
173 int backgroundOffsetX = getScrollX();
174 Drawable drawable = ApiCompatibilityUtils.getDrawable(
Ted C 2017/07/17 21:25:31 we might want to save this to a class variable as
Daniel Park 2017/07/19 00:30:09 Done.
175 getResources(), R.drawable.white_with_rounded_corners);
176 drawable.mutate();
177 drawable.setBounds(
178 backgroundOffsetX, 0, canvas.getWidth() + backgroundOffsetX, mCl ipHeight);
179 drawable.draw(canvas);
180 super.onDraw(canvas);
80 } 181 }
81 } 182 }
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