@@ -32,17 +32,28 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
3232 public interface Callback {
3333 View getChildAtPosition (MotionEvent ev );
3434 View getChildAtPosition (float x , float y );
35+ boolean canChildBeExpanded (View v );
3536 }
3637
3738 private static final String TAG = "ExpandHelper" ;
3839 protected static final boolean DEBUG = false ;
3940 private static final long EXPAND_DURATION = 250 ;
4041
42+ // amount of overstretch for maximum brightness expressed in U
43+ // 2f: maximum brightness is stretching a 1U to 3U, or a 4U to 6U
44+ private static final float STRETCH_INTERVAL = 2f ;
45+
46+ // level of glow for a touch, without overstretch
47+ // overstretch fills the range (GLOW_BASE, 1.0]
48+ private static final float GLOW_BASE = 0.5f ;
49+
4150 @ SuppressWarnings ("unused" )
4251 private Context mContext ;
4352
4453 private boolean mStretching ;
4554 private View mCurrView ;
55+ private View mCurrViewTopGlow ;
56+ private View mCurrViewBottomGlow ;
4657 private float mOldHeight ;
4758 private float mNaturalHeight ;
4859 private float mInitialTouchSpan ;
@@ -53,7 +64,7 @@ public interface Callback {
5364
5465 private int mSmallSize ;
5566 private int mLargeSize ;
56-
67+ private float mMaximumStretch ;
5768
5869 private class ViewScaler {
5970 View mView ;
@@ -62,7 +73,7 @@ public void setView(View v) {
6273 mView = v ;
6374 }
6475 public void setHeight (float h ) {
65- Log .v (TAG , "SetHeight: setting to " + h );
76+ if ( DEBUG ) Log .v (TAG , "SetHeight: setting to " + h );
6677 ViewGroup .LayoutParams lp = mView .getLayoutParams ();
6778 lp .height = (int )h ;
6879 mView .setLayoutParams (lp );
@@ -94,6 +105,7 @@ public int getNaturalHeight(int maximum) {
94105
95106 public ExpandHelper (Context context , Callback callback , int small , int large ) {
96107 mSmallSize = small ;
108+ mMaximumStretch = mSmallSize * STRETCH_INTERVAL ;
97109 mLargeSize = large ;
98110 mContext = context ;
99111 mCallback = callback ;
@@ -120,10 +132,16 @@ public boolean onScale(ScaleGestureDetector detector) {
120132 float h = Math .abs (detector .getCurrentSpanY ());
121133 if (DEBUG ) Log .d (TAG , "current span is: " + h );
122134 h = h + mOldHeight - mInitialTouchSpan ;
135+ float target = h ;
136+ if (DEBUG ) Log .d (TAG , "target is: " + target );
123137 h = h <mSmallSize ?mSmallSize :(h >mLargeSize ?mLargeSize :h );
124138 h = h >mNaturalHeight ?mNaturalHeight :h ;
125139 if (DEBUG ) Log .d (TAG , "scale continues: h=" + h );
126140 mScaler .setHeight (h );
141+ float stretch = (float ) Math .abs ((target - h ) / mMaximumStretch );
142+ float strength = 1f / (1f + (float ) Math .pow (Math .E , -1 * ((8f * stretch ) - 5f )));
143+ if (DEBUG ) Log .d (TAG , "stretch: " + stretch + " strength: " + strength );
144+ setGlow (GLOW_BASE + strength * (1f - GLOW_BASE ));
127145 return true ;
128146 }
129147
@@ -136,6 +154,14 @@ public void onScaleEnd(ScaleGestureDetector detector) {
136154 }
137155 });
138156 }
157+ public void setGlow (float glow ) {
158+ if (mCurrViewTopGlow != null ) {
159+ mCurrViewTopGlow .setAlpha (glow );
160+ }
161+ if (mCurrViewBottomGlow != null ) {
162+ mCurrViewBottomGlow .setAlpha (glow );
163+ }
164+ }
139165
140166 public boolean onInterceptTouchEvent (MotionEvent ev ) {
141167 if (DEBUG ) Log .d (TAG , "interceptTouch: act=" + (ev .getAction ()) +
@@ -154,7 +180,7 @@ public boolean onTouchEvent(MotionEvent ev) {
154180 case MotionEvent .ACTION_UP :
155181 case MotionEvent .ACTION_CANCEL :
156182 mStretching = false ;
157- mCurrView = null ;
183+ clearView () ;
158184 break ;
159185 }
160186 return true ;
@@ -163,14 +189,20 @@ private boolean initScale(View v) {
163189 if (v != null ) {
164190 if (DEBUG ) Log .d (TAG , "scale begins on view: " + v );
165191 mStretching = true ;
166- mCurrView = v ;
192+ setView (v );
193+ setGlow (GLOW_BASE );
167194 mScaler .setView (v );
168195 mOldHeight = mScaler .getHeight ();
169- mNaturalHeight = mScaler .getNaturalHeight (mLargeSize );
196+ if (mCallback .canChildBeExpanded (v )) {
197+ if (DEBUG ) Log .d (TAG , "working on an expandable child" );
198+ mNaturalHeight = mScaler .getNaturalHeight (mLargeSize );
199+ } else {
200+ if (DEBUG ) Log .d (TAG , "working on a non-expandable child" );
201+ mNaturalHeight = mOldHeight ;
202+ }
170203 if (DEBUG ) Log .d (TAG , "got mOldHeight: " + mOldHeight +
171204 " mNaturalHeight: " + mNaturalHeight );
172205 v .getParent ().requestDisallowInterceptTouchEvent (true );
173- if (DEBUG ) v .setBackgroundColor (0xFFFFFF00 );
174206 }
175207 return mStretching ;
176208 }
@@ -183,11 +215,33 @@ private void finishScale(boolean force) {
183215 } else {
184216 h = (force || h < mNaturalHeight ) ? mSmallSize : mNaturalHeight ;
185217 }
186- if (DEBUG ) mCurrView .setBackgroundColor (0 );
218+ if (DEBUG && mCurrView != null ) mCurrView .setBackgroundColor (0 );
187219 mAnimation = ObjectAnimator .ofFloat (mScaler , "height" , h ).setDuration (EXPAND_DURATION );
188220 mAnimation .start ();
189221 mStretching = false ;
222+ setGlow (0f );
223+ clearView ();
224+ }
225+
226+ private void clearView () {
190227 mCurrView = null ;
228+ mCurrViewTopGlow = null ;
229+ mCurrViewBottomGlow = null ;
230+ }
231+
232+ private void setView (View v ) {
233+ mCurrView = null ;
234+ if (v instanceof ViewGroup ) {
235+ ViewGroup g = (ViewGroup ) v ;
236+ mCurrViewTopGlow = g .findViewById (R .id .top_glow );
237+ mCurrViewBottomGlow = g .findViewById (R .id .bottom_glow );
238+ if (DEBUG ) {
239+ String debugLog = "Looking for glows: " +
240+ (mCurrViewTopGlow != null ? "found top " : "didn't find top" ) +
241+ (mCurrViewBottomGlow != null ? "found bottom " : "didn't find bottom" );
242+ Log .v (TAG , debugLog );
243+ }
244+ }
191245 }
192246
193247 @ Override
0 commit comments