66import android .os .Looper ;
77import android .util .Log ;
88import android .view .View ;
9- import android .view .animation .AccelerateInterpolator ;
109import android .view .animation .DecelerateInterpolator ;
1110import android .view .animation .Interpolator ;
1211import android .view .animation .LinearInterpolator ;
2827
2928final class StackHelper implements ValueAnimator .AnimatorUpdateListener {
3029
31- private static long clickMills = System .currentTimeMillis ();
30+ private long clickMills = System .currentTimeMillis ();
3231 private ScheduledThreadPoolExecutor executor ;
3332 /** 判定为滑动的阈值,单位是像素 */
3433 private final int mTouchSlop ;
3534 private int swipModel = MODEL_NONE ;
35+ /** true:顶层将移除,false:顶层将加新*/
36+ private boolean isTopRemove ;
3637 private LinkedList <WeakReference <View >> weakViews = new LinkedList <>();
3738 private List <Integer > originX = new ArrayList <>();
3839 private ReleaseAnimator mAnimator = new ReleaseAnimator ();
@@ -44,26 +45,25 @@ final class StackHelper implements ValueAnimator.AnimatorUpdateListener{
4445 private boolean enableScroll = false ;
4546 private int displayPosition = 0 ;
4647 private StackLayout layout ;
48+ private boolean debug = false ;
4749
4850 StackHelper (int touchSlop ) {
4951 mTouchSlop = touchSlop ;
5052 }
5153
5254 void bindLayout (StackLayout layout ) {
53- //log("bindLayout...");
5455 if (this .layout == null ) {
5556 this .layout = layout ;
5657 }
5758 setAutoPlay (this .layout .stackLooper );
5859 }
5960
6061 void unbindLayout () {
61- //log("unbindLayout...");
6262 setAutoPlay (false );
6363 }
6464
6565 void measureChild (int width ,int height ){
66- log ("measue..." );
66+ // log("measue...");
6767 if (layout != null && layout .getAdapter () != null && layout .getAdapter ().getItemCount () > 0 ){
6868 int size = layout .getRealStackSize ();
6969 if (originX .isEmpty ()) {
@@ -93,33 +93,48 @@ void measureChild(int width,int height){
9393 }
9494
9595 void layoutChild (){
96- log ("layout..." +layout .getChildCount ());
96+ // log("layout..."+layout.getChildCount());
9797 if (needRelayout && layout != null ) {
9898 needRelayout = false ;
99- //log("childCount="+layout.getChildCount());
100- for (int i = 0 , size = layout .getChildCount (); i < size && i < layout .stackSize ; i ++) {
99+ int childSize = layout .getChildCount ();
100+ int stackSize = layout .stackSize ;
101+ for (int i = 0 ; i < childSize ; i ++) {
102+ int top , bottom , left , right , pivot ;
101103 View view = layout .getChildAt (i );
102- int x = originX .get (i );
103- int top ,bottom ,left , right , pivot ;
104- if (layout .stackEdgeModel == MODEL_LEFT ) {
105- left = x ;
106- right = everyWidth + x ;
107- pivot = layout .stackEdge ;
108- } else {
109- right = layout .getWidth () - x ;
110- left = right - everyWidth ;
111- pivot = layout .getWidth () - layout .stackEdge ;
112- }
113104 top = layout .getPaddingTop ();
114105 bottom = everyHeight + top ;
115- left += layout .getPaddingLeft ();
116- view .setPivotX (pivot );
117- view .setPivotY (everyHeight / 2 );
118- view .layout (left , top , right , bottom );
119- if (i < size - 1 ) {
120- view .setScaleY (getChildScale (i ,layout .stackZoomY ));
121- } else {
122- view .setScaleY (1f );
106+ if (i < stackSize ) {
107+ int x = originX .get (i );
108+ if (layout .stackEdgeModel == MODEL_LEFT ) {
109+ left = x ;
110+ right = everyWidth + left ;
111+ pivot = layout .stackEdge ;
112+ } else {
113+ right = layout .getWidth () - x ;
114+ left = right - everyWidth ;
115+ pivot = layout .getWidth () - layout .stackEdge ;
116+ }
117+ view .setPivotX (pivot );
118+ view .setPivotY (everyHeight / 2 );
119+ view .layout (left , top , right , bottom );
120+ view .setScaleY (getChildScale (i , layout .stackZoomY ));
121+ if (view .getTranslationX () != 0f ){
122+ if (i +1 < stackSize ){
123+ view .setTranslationX (0 );
124+ }else if (i +1 == stackSize && childSize == stackSize ){//恢复stackSize时,补偿距离
125+ float distance = layout .stackEdgeModel == MODEL_RIGHT ? -everyWidth : everyWidth ;
126+ view .setTranslationX (view .getTranslationX ()+distance );
127+ }
128+ }
129+ }else if (!isTopRemove ){//顶层加入
130+ if (layout .stackEdgeModel == MODEL_LEFT ) {
131+ left = layout .getWidth () - layout .stackEdge ;
132+ right = everyWidth + left ;
133+ }else {
134+ right = layout .stackEdge ;
135+ left = right - everyWidth ;
136+ }
137+ view .layout (left , top , right , bottom );
123138 }
124139 }
125140 }
@@ -173,7 +188,8 @@ private void removeStackView(View view){
173188 if (view != null && layout != null ) {
174189 layout .removeView (view );
175190 view .setTranslationX (0 );
176- weakViews .add (new WeakReference <View >(view ));
191+ view .setScaleY (1f );
192+ weakViews .add (new WeakReference <>(view ));
177193 }
178194 }
179195
@@ -212,16 +228,21 @@ void fingerTouchDown(){
212228 void executeScroll (int dx ) {
213229 //dx<0 left, dx>0 right
214230 if (layout .getChildCount () > 0 && !mAnimator .isRunning ()) {
231+ View view ;
215232 //判断滑动方向
216- if (swipModel == MODEL_NONE ){
233+ if (MODEL_NONE == swipModel ){
217234 swipModel = dx < 0 ? MODEL_LEFT : MODEL_RIGHT ;
235+ isTopRemove = layout .stackEdgeModel != swipModel ;
236+ if (isTopRemove ){
237+ view = layout .getChildAt (layout .getChildCount ()-1 );
238+ }else {
239+ view = addTopView ();
240+ }
241+ mAnimator .setAnimatorView (view );
242+ }else {
243+ view = mAnimator .mAnimatorView ;
218244 }
219- for (int size = layout .getChildCount (), i = size - 1 ; i < size ; i ++) {
220- View itemView = layout .getChildAt (i );
221- itemView .setTranslationX (itemView .getTranslationX () + 0.8f * dx );
222- StackHelper .log ("dx = " + dx + ",view transX = " + itemView .getTranslationX ());
223- mAnimator .setAnimatorView (itemView );
224- }
245+ view .setTranslationX (view .getTranslationX () + 1.0f *everyWidth /layout .getWidth () * dx );
225246 }
226247 }
227248
@@ -232,39 +253,36 @@ void releaseScroll(int velocity){
232253 setAutoPlay (layout .stackLooper );
233254 float transX = mAnimator .getTranslationX ();
234255 if (layout .getAdapter () != null && Math .abs (transX ) > 0 && !mAnimator .isRunning ()) {
235- StackHelper .log ("end = " + transX );
236256 //滑动速度大于限定或者滑动距离大于宽度一部分,移出当前视图可视范围
237- boolean recover = true ;
238257 if (Math .abs (velocity ) >= everyWidth || Math .abs (transX ) > mMaxDistance ){
239- if (MODEL_LEFT == swipModel ){
240- if (isRightMoveOutLeft ()){
241- addBottomView ();
242- recover = false ;
243- }else {
244- addTopView ();
245- }
246- }else if (MODEL_RIGHT == swipModel ){
247- if (isLeftMoveOutRight ()){
248- addBottomView ();
249- recover = false ;
250- }else {
251- addTopView ();
252- }
258+ int sign = MODEL_LEFT == swipModel ? -1 : 1 ;
259+ if (isTopRemove ){
260+ addBottomView ();
261+ transX = layout .getWidth ()*sign - transX ;
262+ mAnimator .startAnimator (true ,false ,transX ,mMaxDistance ,this );
263+ }else {
264+ removeBottomView ();
265+ transX = everyWidth *sign - transX ;
266+ mAnimator .startAnimator (false ,false ,transX ,mMaxDistance ,this );
253267 }
254- if (!recover ) {
255- transX = layout .getWidth () * Math .signum (transX ) - transX ;
256- }
257- }
258- if (recover ){//取反恢复原样
268+ }else {
269+ //取反恢复原样
259270 transX *= -1 ;
271+ mAnimator .startAnimator (!isTopRemove ,false ,transX ,mMaxDistance ,this );
260272 }
261- StackHelper .log ("velocity = " + velocity +",end = " + transX + ",distance=" +mMaxDistance + ",needRemoveTopView=" +!recover +
262- ",recover=" + recover + ",swipModel =" + swipModel + ",edgeModel=" + layout .stackEdgeModel );
263- mAnimator .startAnimator (!recover ,false ,transX ,mMaxDistance ,this );
264273 swipModel = MODEL_NONE ;
265274 }
266275 }
267276
277+ void autoScroll (){
278+ if (layout .getChildCount () > 0 && !isFingerTouch && !mAnimator .isRunning ()) {
279+ mAnimator .setAnimatorView (layout .getChildAt (layout .getChildCount () - 1 ));
280+ int transX = (layout .stackEdgeModel == MODEL_LEFT ? 1 : -1 )*layout .getWidth ();
281+ isTopRemove = true ;
282+ mAnimator .startAnimator (true ,true ,transX ,mMaxDistance ,this );
283+ }
284+ }
285+
268286 void setAutoPlay (boolean looper ){
269287 if (looper ) {
270288 if (executor == null || executor .isShutdown ()){
@@ -280,23 +298,7 @@ void setAutoPlay(boolean looper){
280298 }
281299 }
282300
283- void autoScroll (){
284- if (layout .getChildCount () > 0 && !isFingerTouch && !mAnimator .isRunning ()) {
285- mAnimator .setAnimatorView (layout .getChildAt (layout .getChildCount () - 1 ));
286- int transX = (layout .stackEdgeModel == MODEL_LEFT ? 1 : -1 )*layout .getWidth ();
287- mAnimator .startAnimator (true ,true ,transX ,mMaxDistance ,this );
288- }
289- }
290-
291- private boolean isLeftMoveOutRight (){
292- return layout .stackEdgeModel == MODEL_LEFT && swipModel == MODEL_RIGHT ;
293- }
294-
295- private boolean isRightMoveOutLeft (){
296- return layout .stackEdgeModel == MODEL_RIGHT && swipModel == MODEL_LEFT ;
297- }
298-
299- /** 移除顶层 */
301+ /** 加入底层 */
300302 private void addBottomView (){
301303 int cnt = layout .getAdapter ().getItemCount ();
302304 displayPosition += 1 ;
@@ -310,8 +312,30 @@ private void addBottomView(){
310312 }
311313
312314 /** 加入顶层 */
313- private void addTopView (){
315+ private View addTopView (){
316+ int cnt = layout .getAdapter ().getItemCount ();
317+ int position = displayPosition - 1 ;
318+ if (position < 0 ){
319+ position += cnt ;
320+ }
321+ View view = getStackView ();
322+ layout .getAdapter ().onBindView (view , position );
323+ needRelayout = true ;
324+ layout .addView (view );
325+ return view ;
326+ }
314327
328+ /** 移除底层 */
329+ private void removeBottomView (){
330+ int cnt = layout .getAdapter ().getItemCount ();
331+ displayPosition -= 1 ;
332+ if (displayPosition < 0 ){
333+ displayPosition += cnt ;
334+ }
335+ needRelayout = true ;
336+ View view = layout .getChildAt (0 );
337+ removeStackView (view );
338+ layout .getAdapter ().onItemDisplay (displayPosition );
315339 }
316340
317341 @ Override
@@ -357,27 +381,28 @@ float getTranslationX(){
357381
358382 void setTranslationX (float value ){
359383 if (mAnimatorView != null ){
360- mAnimatorView .setTranslationX (mAnimatorView .getTranslationX ()+value -lastValue );
384+ float trans = mAnimatorView .getTranslationX ()+value -lastValue ;
385+ mAnimatorView .setTranslationX (trans );
361386 }
362387 lastValue = value ;
363388 }
364389
365- void startAnimator (boolean needRemove ,boolean needAdd ,float transX , int distance , ValueAnimator .AnimatorUpdateListener listener ){
366- int duration = needAdd ? 500 : (int )(Math .abs (transX )/distance *150 );
367- needAddBottomView = needAdd ;
368- needRemoveTopView = needRemove ;
390+ void startAnimator (boolean needRemoveTop ,boolean needAddBottom ,float transX , int distance , ValueAnimator .AnimatorUpdateListener listener ){
391+ int duration = needAddBottom ? 400 : (int )(Math .abs (transX )/distance *100 );
392+ needAddBottomView = needAddBottom ;
393+ needRemoveTopView = needRemoveTop ;
369394 animator = ValueAnimator .ofFloat (0f , transX ).setDuration (duration );
370- animator .setInterpolator (needAdd ? interpolatorAuto : interpolator );
395+ animator .setInterpolator (needAddBottom ? interpolatorAuto : interpolator );
371396 animator .addUpdateListener (listener );
372397 animator .start ();
373398 }
374399
375400 void endAnimator (StackHelper helper ){
376401 if (needRemoveTopView ) {
377402 helper .removeStackView (mAnimatorView );
378- needRemoveTopView = false ;
379403 }
380404 animator .removeAllUpdateListeners ();
405+ needRemoveTopView = false ;
381406 lastValue = 0f ;
382407 mAnimatorView = null ;
383408 animator = null ;
@@ -421,7 +446,7 @@ public void run() {
421446 }
422447 }
423448
424- static boolean filterClick (){
449+ boolean filterClick (){
425450 long nowMills = System .currentTimeMillis ();
426451 if (nowMills - clickMills > 500 ){
427452 clickMills = nowMills ;
@@ -430,9 +455,11 @@ static boolean filterClick(){
430455 return false ;
431456 }
432457
433- static void log (String msg ){
434- StackTraceElement element = Thread .currentThread ().getStackTrace ()[3 ];
435- Log .e ("StackLayout" ,String .format ("%1$s:%2$s(%3$s):%4$s" ,element .getClassName (),
436- element .getMethodName (),element .getLineNumber (),msg ));
458+ void log (String msg ){
459+ if (debug ) {
460+ StackTraceElement element = Thread .currentThread ().getStackTrace ()[3 ];
461+ Log .e ("StackLayout" , String .format ("%1$s:%2$s(%3$s):%4$s" , element .getClassName (),
462+ element .getMethodName (), element .getLineNumber (), msg ));
463+ }
437464 }
438465}
0 commit comments