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

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: Reverting dimens.xml change. 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.ValueAnimator;
8 import android.animation.ValueAnimator.AnimatorUpdateListener;
9 import android.annotation.SuppressLint;
7 import android.content.Context; 10 import android.content.Context;
11 import android.graphics.Canvas;
12 import android.graphics.Rect;
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 ValueAnimator mAnimator;
28 private int mOldHeight;
29 private int mCanvasWidth;
30 private int mClipHeight;
31
32 // Animation value hits the limit twice if the animation duration is long en ough (by developer
33 // options); this boolean helps to ensure that it only happens once.
34 private boolean mAtMaxAnimationValue;
35
36 private int mDifferenceInHeight = 0;
37 private int mPreviousChildIndex = 1;
19 private final int mContextMenuMinimumPaddingPx = 38 private final int mContextMenuMinimumPaddingPx =
20 getResources().getDimensionPixelSize(R.dimen.context_menu_min_paddin g); 39 getResources().getDimensionPixelSize(R.dimen.context_menu_min_paddin g);
21 40
22 public TabularContextMenuViewPager(Context context) { 41 public TabularContextMenuViewPager(Context context) {
23 super(context); 42 super(context);
24 } 43 }
25 44
26 public TabularContextMenuViewPager(Context context, AttributeSet attrs) { 45 public TabularContextMenuViewPager(Context context, AttributeSet attrs) {
27 super(context, attrs); 46 super(context, attrs);
28 } 47 }
29 48
30 /** 49 /**
31 * Used to show the full ViewPager dialog. Without this the dialog would hav e no height or 50 * Used to show the full ViewPager dialog. Without this the dialog would hav e no height or
32 * width. 51 * width.
33 */ 52 */
34 @Override 53 @Override
35 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 54 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
55 int tabHeight = 0;
36 int menuHeight = 0; 56 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 57
42 // The width of the context menu is defined so that it leaves space betw een itself and the 58 // 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 59 // 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). 60 // across a large display (e.g. a tablet screen).
45 int deviceWidthPx = getResources().getDisplayMetrics().widthPixels; 61 int deviceWidthPx = getResources().getDisplayMetrics().widthPixels;
46 int contextMenuWidth = Math.min(deviceWidthPx - 2 * mContextMenuMinimumP addingPx, 62 int contextMenuWidth = Math.min(deviceWidthPx - 2 * mContextMenuMinimumP addingPx,
47 getResources().getDimensionPixelSize(R.dimen.context_menu_max_wi dth)); 63 getResources().getDimensionPixelSize(R.dimen.context_menu_max_wi dth));
48 64
49 widthMeasureSpec = MeasureSpec.makeMeasureSpec(contextMenuWidth, Measure Spec.EXACTLY); 65 widthMeasureSpec = MeasureSpec.makeMeasureSpec(contextMenuWidth, Measure Spec.EXACTLY);
50 66
51 // The height of the context menu is calculated as the sum of: 67 // 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 68 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 69
58 child.measure( 70 // Handles the case where this is called while the pager is scrolling be tween views.
59 widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec .UNSPECIFIED)); 71 if (getScrollX() != 0 && getScrollX() != mCanvasWidth) {
60 int measuredHeight = child.getMeasuredHeight(); 72 heightMeasureSpec = MeasureSpec.makeMeasureSpec(mOldHeight, MeasureS pec.EXACTLY);
73 } else {
74 // The height of the context menu is calculated as the sum of:
75 // 1. The tab bar's height, which is only visible when the context m enu requires it
76 // (i.e. an ImageLink is clicked)
77 // 2. The height of the View being displayed for the current tab.
78 for (int i = 0; i < getChildCount(); i++) {
79 View child = getChildAt(i);
80 child.measure(
81 widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, Measure Spec.UNSPECIFIED));
82 int measuredHeight = child.getMeasuredHeight();
61 83
62 // The ViewPager also considers the tab layout one of its children, and needs to be 84 // The ViewPager also considers the tab layout one of its childr en, and needs to be
63 // treated separately from getting the largest height. 85 // treated separately from getting the largest height.
64 if (child.getId() == R.id.tab_layout && child.getVisibility() != GON E) { 86 if (child.getId() == R.id.tab_layout && child.getVisibility() != GONE) {
65 tabHeight = measuredHeight; 87 tabHeight = measuredHeight;
66 } else if (i == currentItemsIndex) { 88 } else if (i == currentChildIndex) {
67 menuHeight = child.getMeasuredHeight(); 89 menuHeight = child.getMeasuredHeight();
68 break; 90 break;
91 }
92 }
93 int fullHeight = menuHeight + tabHeight;
94 int deviceHeightPx = getResources().getDisplayMetrics().heightPixels ;
Theresa 2017/07/14 16:56:38 nit: This is technically the current available hei
Daniel Park 2017/07/14 23:15:40 Done.
95 fullHeight = Math.min(fullHeight, deviceHeightPx - 2 * mContextMenuM inimumPaddingPx);
96 mDifferenceInHeight = fullHeight - mOldHeight;
97
98 if (currentChildIndex == mPreviousChildIndex) {
99 // Handles the case where the height of the current tab changes (i.e. an image
100 // finished loading or the link became fully visible).
Theresa 2017/07/14 16:56:38 The CL description says "Note: this does not handl
Daniel Park 2017/07/14 23:15:39 Done.
101 mClipHeight = fullHeight;
102 if (menuHeight != 0) {
103 mOldHeight = fullHeight;
Theresa 2017/07/14 16:56:38 nit: this can fit on the line above if (menuHeigh
Daniel Park 2017/07/14 23:15:40 Done.
104 }
105 heightMeasureSpec = MeasureSpec.makeMeasureSpec(fullHeight, Meas ureSpec.EXACTLY);
106 // Clip logic is not called on orientation changes, so it must b e set here.
107 setClipDimensionsForResize(contextMenuWidth);
108 } else {
109 // Handles the case where the view pager has completely scrolled to a different
110 // child.
111 if (mAnimator == null) {
112 initAnimator();
Theresa 2017/07/14 16:56:38 nit: this can also fit on the line above
Daniel Park 2017/07/14 23:15:40 Done.
113 }
114 mAnimator.start();
115 heightMeasureSpec = MeasureSpec.makeMeasureSpec(
Theresa 2017/07/14 16:56:38 Should we measure before starting the animation?
Daniel Park 2017/07/14 23:15:39 Done.
116 Math.max(mOldHeight, fullHeight), MeasureSpec.EXACTLY);
69 } 117 }
70 } 118 }
119 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
120 mPreviousChildIndex = currentChildIndex;
121 }
71 122
72 // Cap the height of the context menu so that it fits on the screen with out touching the 123 @SuppressLint("NewApi")
Theresa 2017/07/14 16:56:38 This is a real warning. It looks like setClipBound
Daniel Park 2017/07/14 23:15:39 Acknowledged. I added a todo. I'll play around wit
Ted C 2017/07/17 21:25:31 As you are already overwriting onDraw, you should
Daniel Park 2017/07/19 00:30:08 Done.
73 // screen's edges. 124 public void setClipDimensionsForResize(int width) {
74 int fullHeight = menuHeight + tabHeight; 125 setClipBounds(new Rect(0, 0, width, mClipHeight));
75 int deviceHeightPx = getResources().getDisplayMetrics().heightPixels; 126 }
76 fullHeight = Math.min(fullHeight, deviceHeightPx - 2 * mContextMenuMinim umPaddingPx);
77 127
78 heightMeasureSpec = MeasureSpec.makeMeasureSpec(fullHeight, MeasureSpec. EXACTLY); 128 @SuppressLint("NewApi")
79 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 129 private void initAnimator() {
130 mAnimator = ValueAnimator.ofFloat(0f, 1f);
131 mAnimator.setDuration(250);
Theresa 2017/07/14 16:56:38 nit: This should be a static final int at the top
Daniel Park 2017/07/14 23:15:40 Done.
132 mAnimator.setInterpolator(new LinearOutSlowInInterpolator());
133 mAnimator.addUpdateListener(new AnimatorUpdateListener() {
134
135 @Override
136 public void onAnimationUpdate(ValueAnimator animation) {
137 float animatedValue = (float) animation.getAnimatedValue();
138 if (animatedValue == 0) {
139 mAtMaxAnimationValue = false;
Theresa 2017/07/14 16:56:38 Instead of keeping a class variable, you could jus
Daniel Park 2017/07/14 23:15:39 Done.
140 }
141 if (!mAtMaxAnimationValue) {
142 if (mDifferenceInHeight < 0) {
143 setTranslationY(animatedValue * -mDifferenceInHeight / 2 );
144 } else {
145 setTranslationY((1 - animatedValue) * mDifferenceInHeigh t / 2);
146 }
147 mClipHeight = mOldHeight + (int) (mDifferenceInHeight * anim atedValue);
148 setClipBounds(new Rect(0, 0, mCanvasWidth, mClipHeight));
149 invalidate();
150 }
151 if (animatedValue == 1) {
152 mAtMaxAnimationValue = true;
Theresa 2017/07/14 16:56:38 It's more customary for us to do this sort of thin
Daniel Park 2017/07/14 23:15:40 Done.
153 mOldHeight = mClipHeight;
154 requestLayout();
155 setTranslationY(0);
156 }
157 }
158 });
159 }
160
161 @Override
162 public void onDraw(Canvas canvas) {
163 mCanvasWidth = canvas.getWidth();
164 int backgroundOffsetX = getScrollX();
165 Drawable drawable = ApiCompatibilityUtils.getDrawable(
166 getResources(), R.drawable.white_with_rounded_corners);
167 drawable.setBounds(
Theresa 2017/07/14 16:56:38 You should call drawable.mutate() before setting t
Daniel Park 2017/07/14 23:15:40 Done.
168 backgroundOffsetX, 0, canvas.getWidth() + backgroundOffsetX, mCl ipHeight);
169 drawable.draw(canvas);
170 super.onDraw(canvas);
80 } 171 }
81 } 172 }
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