Android UI效果實現——Activity滑動退出效果

更新說明:android

一、在QQ網友北京-旭的提醒下,在SlideFrame的initilize方法中添加了focusable、focusableInTouch、clickable的狀態設置,不然會致使部分狀況下沒法滑動,感謝!api

 

1、效果動圖app

 

2、使用說明框架

使用方法很簡單,只有一個類HorizontalActivity,繼承自FragmentActivity類,實現了contentView的滑動事件觸發和動畫效果,要在本身的代碼裏實現,方法兩種:ide

一、若是對Activity沒特殊要求,直接繼承HorizontalActivity便可動畫

二、若是Activity的父類必須是某一特定類型的Activity子類,則能夠仿照個人寫法對該類進行繼承ui

 

3、HorizontalActivity類的代碼this

  1 package com.beifeng.widget;
  2 
  3 import android.content.Context;
  4 import android.support.v4.app.FragmentActivity;
  5 import android.util.AttributeSet;
  6 import android.view.LayoutInflater;
  7 import android.view.MotionEvent;
  8 import android.view.View;
  9 import android.view.ViewGroup.LayoutParams;
 10 import android.view.animation.Animation;
 11 import android.view.animation.Animation.AnimationListener;
 12 import android.view.animation.DecelerateInterpolator;
 13 import android.view.animation.Transformation;
 14 import android.widget.FrameLayout;
 15 
 16 /**
 17  * HorizontalActivity:可滑動Activity
 18  * 
 19  * 注意事項: 本Activity中與滑動方向相同的滑動操做會被攔截
 20  * 
 21  * @author HalfmanG2
 22  * @version 1.0.0
 23  * @since JDK7 SDK19
 24  */
 25 public class HorizontalActivity extends FragmentActivity {
 26 
 27     /** 框架視圖 */
 28     protected SlideFrame frameView;
 29     /** 內容視圖 */
 30     protected View contentView;
 31 
 32     @Override
 33     public void setContentView(int layoutResID) {
 34         // 初始化frame
 35         if (frameView == null) {
 36             // 未初始化則初始化
 37             frameView = new SlideFrame(this);
 38         } else {
 39             // 已經初始化則清空
 40             frameView.removeAllViews();
 41         }
 42         // 創造framelayout的填充參數
 43         FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(-1, -1);
 44         // 獲取layoutResId對應的contentView視圖並插入frameView
 45         LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 46         contentView = inflater.inflate(layoutResID, null);
 47         frameView.addView(contentView, params);
 48         // 設置frameview爲根視圖
 49         super.setContentView(frameView);
 50     }
 51 
 52     @Override
 53     public void setContentView(View view) {
 54         // 初始化frame
 55         if (frameView == null) {
 56             // 未初始化則初始化
 57             frameView = new SlideFrame(this);
 58         } else {
 59             // 已經初始化則清空
 60             frameView.removeAllViews();
 61         }
 62         // 創造framelayout的填充參數
 63         FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(-1, -1);
 64         // 獲取view爲contentView視圖並插入frameView
 65         contentView = view;
 66         frameView.addView(contentView, params);
 67         // 設置frameview爲根視圖
 68         super.setContentView(frameView);
 69     }
 70 
 71     @Override
 72     public void setContentView(View view, LayoutParams params) {
 73         // 初始化frame
 74         if (frameView == null) {
 75             // 未初始化則初始化
 76             frameView = new SlideFrame(this);
 77         } else {
 78             // 已經初始化則清空
 79             frameView.removeAllViews();
 80         }
 81         // 創造framelayout的填充參數
 82         FrameLayout.LayoutParams fp = new FrameLayout.LayoutParams(-1, -1);
 83         // 獲取view爲contentView視圖並插入frameView
 84         contentView = view;
 85         frameView.addView(contentView, fp);
 86         // 設置frameview爲根視圖
 87         super.setContentView(frameView, params);
 88     }
 89 
 90     /**
 91      * 推出頁面
 92      */
 93     protected void onSlideFinish() {
 94         finish();
 95     }
 96 
 97     /**
 98      * 位移內容視圖到
 99      * 
100      * @param position
101      *            目標位置
102      */
103     public void slideTo(int position) {
104         if (android.os.Build.VERSION.SDK_INT > 10) {
105             contentView.setX(position);
106         } else {
107             android.widget.FrameLayout.LayoutParams params = (android.widget.FrameLayout.LayoutParams) contentView
108                     .getLayoutParams();
109             params.setMargins(position, 0, -position, 0);
110             contentView.setLayoutParams(params);
111         }
112     }
113 
114     /**
115      * 得到當前容器位移
116      * 
117      * @return 當前容器位移
118      */
119     public int getSlide() {
120         if (android.os.Build.VERSION.SDK_INT > 10) {
121             return (int) contentView.getX();
122         } else {
123             return ((android.widget.FrameLayout.LayoutParams) contentView
124                     .getLayoutParams()).leftMargin;
125         }
126     }
127 
128     /**
129      * 滑動框架
130      * 
131      * @author HalfmanG2
132      * @version 1.0.0
133      * @since JDK7 SDK19
134      */
135     public class SlideFrame extends FrameLayout {
136         /** 默認滑動閥值 */
137         private final static int DEFAULT_SLIDE_DUMPING = 8;
138         /** 默認狀態改變閥值 */
139         private final static int DEFAULT_DO_DUMPING = 100;
140         /** 滑動起始位置與當前位置 */
141         private int startX, currentX, startY, currentY;
142         /** 是否攔截事件,是否已經完成滑動檢查 */
143         private boolean doNotIntercept, hasChecked;
144         /** 滑動閥值 */
145         private int slideDumping;
146         /** 操做閥值 */
147         private int doDumping;
148         /** 滑屏動畫 */
149         protected SlideAnimation slideAnimation;
150 
151         @Override
152         public boolean onInterceptTouchEvent(MotionEvent ev) {
153             super.onInterceptTouchEvent(ev);
154             // 若當前處在側滑狀態中,則攔截信號
155             if ((!doNotIntercept) && hasChecked) {
156                 return true;
157             }
158             // 不然使用默認
159             return false;
160         }
161 
162         @Override
163         public boolean dispatchTouchEvent(MotionEvent ev) {
164             if (ev.getAction() == MotionEvent.ACTION_DOWN) {
165                 // 得到起始滑動座標
166                 startX = (int) ev.getX();
167                 startY = (int) ev.getY();
168                 // 初始化狀態
169                 doNotIntercept = false;
170                 hasChecked = false;
171             } else if (!doNotIntercept) {
172                 // 得到當前滑動座標
173                 currentX = (int) ev.getX();
174                 currentY = (int) ev.getY();
175                 // 根據滑動類型區分
176                 switch (ev.getAction()) {
177                 case MotionEvent.ACTION_MOVE: // 移動狀態
178                     if (hasChecked) {
179                         doSlide();
180                     } else {
181                         doCheck();
182                     }
183                     break;
184                 case MotionEvent.ACTION_CANCEL: // 取消狀態
185                 case MotionEvent.ACTION_UP: // 擡起狀態
186                     // 初始化狀態
187                     doNotIntercept = false;
188                     hasChecked = false;
189                     if (Math.abs(currentX - startX) > doDumping) {
190                         if (currentX > startX) {
191                             // 右滑
192                             slideAnimation = new SlideAnimation(getSlide(),
193                                     contentView.getWidth(), 0);
194                             slideAnimation
195                                     .setAnimationListener(new AnimationListener() {
196                                         @Override
197                                         public void onAnimationStart(
198                                                 Animation animation) {
199                                         }
200 
201                                         @Override
202                                         public void onAnimationRepeat(
203                                                 Animation animation) {
204                                         }
205 
206                                         @Override
207                                         public void onAnimationEnd(
208                                                 Animation animation) {
209                                             onSlideFinish();
210                                         }
211                                     });
212                             startAnimation(slideAnimation);
213                         }
214                     } else {
215                         // 返回0位置
216                         slideAnimation = new SlideAnimation(getSlide(), 0, 0);
217                         startAnimation(slideAnimation);
218                     }
219                     break;
220                 default:
221                     break;
222                 }
223             }
224             return super.dispatchTouchEvent(ev);
225         }
226 
227         /**
228          * 檢查是否超過滑動閥值開啓滑動狀態
229          */
230         private void doCheck() {
231             if (Math.abs(startY - currentY) > slideDumping) {
232                 hasChecked = true;
233                 doNotIntercept = true;
234                 slideTo(0);
235             } else if (currentX - startX > slideDumping) {
236                 hasChecked = true;
237                 doNotIntercept = false;
238             }
239         }
240 
241         /**
242          * 進行滑動
243          */
244         private void doSlide() {
245             if (currentX > startX) {
246                 slideTo(currentX - startX);
247             } else {
248                 slideTo(0);
249             }
250         }
251 
252         /**
253          * 設置滑動閥值
254          * 
255          * @param dpValue
256          */
257         public void setSlideDumping(int dpValue) {
258             slideDumping = dip2px(dpValue);
259         }
260 
261         /**
262          * 設置狀態改變閥值
263          * 
264          * @param dpValue
265          */
266         public void setDoDumping(int dpValue) {
267             doDumping = dip2px(dpValue);
268         }
269 
270         /**
271          * 二級構造方法
272          */
273         private void initilize() {
274             setSlideDumping(DEFAULT_SLIDE_DUMPING);
275             setDoDumping(DEFAULT_DO_DUMPING);
276             doNotIntercept = false;
277             hasChecked = false;
278             setClickable(true);
279             setFocusable(true);
280             setFocusableInTouchMode(true);
281         }
282 
283         /**
284          * 構造方法
285          * 
286          * @param context
287          * @param attrs
288          * @param defStyle
289          */
290         public SlideFrame(Context context, AttributeSet attrs, int defStyle) {
291             super(context, attrs, defStyle);
292             initilize();
293         }
294 
295         /**
296          * 構造方法
297          * 
298          * @param context
299          * @param attrs
300          */
301         public SlideFrame(Context context, AttributeSet attrs) {
302             super(context, attrs);
303             initilize();
304         }
305 
306         /**
307          * 構造方法
308          * 
309          * @param context
310          */
311         public SlideFrame(Context context) {
312             super(context);
313             initilize();
314         }
315 
316         /**
317          * 講dip值轉換爲px值,像素密度距離轉像素距離
318          * 
319          * @param dipValue dp值
320          * @return px值
321          */
322         private int dip2px(float dipValue) {
323             // 得到像素密度
324             final float scale = getContext().getResources().getDisplayMetrics().density;
325             // 四捨五入dp值乘像素密度
326             return (int) (dipValue * scale + 0.5f);
327         }
328     }
329 
330     /**
331      * 滑動動畫類
332      * 
333      * @author HalfmanG2
334      */
335     public class SlideAnimation extends Animation {
336         /** 起始位置,目標位置 */
337         private float from, to;
338         /**
339          * 構造方法
340          * @param from 起始位置
341          * @param to 目標位置
342          * @param startOffset 起始延遲
343          */
344         public SlideAnimation(int from, int to, int startOffset) {
345             this.from = from;
346             this.to = to;
347             setFillEnabled(false);
348             setDuration(200);
349             setRepeatCount(0);
350             setStartOffset(startOffset);
351             setInterpolator(new DecelerateInterpolator());
352         }
353         @Override
354         protected void applyTransformation(float interpolatedTime,
355                 Transformation t) {
356             float current = from + (to - from) * interpolatedTime;
357             slideTo((int) current);
358             super.applyTransformation(interpolatedTime, t);
359         }
360     }
361 }

 

4、使用詳細步驟spa

一、創建一個Android工程,項目最小api level必須在api level 11及以上code

二、把本類考入任意代碼包下

三、項目中想要實現Activity滑動退出效果的Activity繼承本類

四、若是要在滑動過程當中顯示上一個Activity的話,將Activity的背景設置爲透明,方法建議經過設置Activity的Style或者說theme來實現

五、若是滑動過程當中須要加入一些特殊效果,能夠複寫slideTo(int)方法,記得別把super.slideTo(int)給漏了,不然滑動失效

六、若是滑動結束後不但願當即返回上一頁,能夠複寫onSlideFinish()方法

 

PS、

很簡單的實現方法,但離我以爲完美還太遠,因此若是有更好的實現方法但願能夠一塊兒交流下:

聯繫方式QQ:811868948,備註加上Android交流,有好的想法必定要聯繫我,謝謝!

聯繫方式E-Mail:halfmanhuang@gmail.com

相關文章
相關標籤/搜索