一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Android - Android仿人人客戶端滑動菜單的側(cè)滑菜單效果

Android仿人人客戶端滑動菜單的側(cè)滑菜單效果

2022-02-17 17:24guolin Android

這篇文章主要介紹了Android仿人人客戶端滑動菜單的側(cè)滑特效實現(xiàn)代碼,小編覺得挺不錯的,分享給大家供大家參考

人人客戶端有一個特效還是挺吸引人的,在主界面手指向右滑動,就可以將菜單展示出來,而主界面會被隱藏大部分,但是仍有左側(cè)的一小部分同菜單一起展示。

據(jù)說人人客戶端的這個特效是從facebook客戶端模仿來的,至于facebook是不是又從其它地方模仿來的就不得而知了。好,今天我們就一起來實現(xiàn)這個效果,總之我第一次看到這個特效是在人人客戶端看到的,我也就主觀性地認為我是在模仿人人客戶端的特效了。

雖然現(xiàn)在網(wǎng)上類似這種效果的實現(xiàn)也非常多,可是我發(fā)現(xiàn)實現(xiàn)方案大都非常復(fù)雜,并不容易理解。但其實這種效果并不難實現(xiàn),因此我今天給大家?guī)淼囊彩鞘飞献詈唵蔚幕瑒硬藛螌崿F(xiàn)方案。

首先還是講一下實現(xiàn)原理。在一個Activity的布局中需要有兩部分,一個是菜單(menu)的布局,一個是內(nèi)容(content)的布局。兩個布局橫向排列,菜單布局在左,內(nèi)容布局在右。初始化的時候?qū)⒉藛尾季窒蜃笃?,以至于能夠完全隱藏,這樣內(nèi)容布局就會完全顯示在Activity中。然后通過監(jiān)聽手指滑動事件,來改變菜單布局的左偏移距離,從而控制菜單布局的顯示和隱藏。

原理圖如下:

Android仿人人客戶端滑動菜單的側(cè)滑菜單效果
 

將菜單布局的左偏移值改成0時。

效果圖如下:

Android仿人人客戶端滑動菜單的側(cè)滑菜單效果

好,我們開始用代碼來實現(xiàn)。首先在Eclipse中新建一個Android項目,項目名就叫做RenRenSlideMenuDemo。然后寫一下布局文件,創(chuàng)建或打開layout目錄下的activity_main.xml文件,加入如下代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:orientation="horizontal"
 tools:context=".MainActivity" >
 <LinearLayout
 android:id="@+id/menu"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:background="@drawable/menu" >
 </LinearLayout>
 <LinearLayout
 android:id="@+id/content"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:background="@drawable/content" >
 </LinearLayout>
</LinearLayout>

這個布局文件的最外層布局是一個LinearLayout,排列方向是水平方向排列。這個LinearLayout下面嵌套了兩個子LinearLayout,分別就是菜單的布局和內(nèi)容的布局。這里為了要讓布局盡量簡單,菜單布局和內(nèi)容布局里面沒有加入任何控件,只是給這兩個布局各添加了一張背景圖片,這兩張背景圖片是我從人人客戶端上截下來的圖。這樣我們可以把注意力都集中在如何實現(xiàn)滑動菜單的效果上面,不用關(guān)心里面各種復(fù)雜的布局了。

創(chuàng)建或打開MainActivity,這個類仍然是程序的主Activity,也是這次demo唯一的Activity,在里面加入如下代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
public class MainActivity extends Activity implements OnTouchListener {
 
 /**
 * 滾動顯示和隱藏menu時,手指滑動需要達到的速度。
 */
 public static final int SNAP_VELOCITY = 200;
 
 /**
 * 屏幕寬度值。
 */
 private int screenWidth;
 
 /**
 * menu最多可以滑動到的左邊緣。值由menu布局的寬度來定,marginLeft到達此值之后,不能再減少。
 */
 private int leftEdge;
 
 /**
 * menu最多可以滑動到的右邊緣。值恒為0,即marginLeft到達0之后,不能增加。
 */
 private int rightEdge = 0;
 
 /**
 * menu完全顯示時,留給content的寬度值。
 */
 private int menuPadding = 80;
 
 /**
 * 主內(nèi)容的布局。
 */
 private View content;
 
 /**
 * menu的布局。
 */
 private View menu;
 
 /**
 * menu布局的參數(shù),通過此參數(shù)來更改leftMargin的值。
 */
 private LinearLayout.LayoutParams menuParams;
 
 /**
 * 記錄手指按下時的橫坐標(biāo)。
 */
 private float xDown;
 
 /**
 * 記錄手指移動時的橫坐標(biāo)。
 */
 private float xMove;
 
 /**
 * 記錄手機抬起時的橫坐標(biāo)。
 */
 private float xUp;
 
 /**
 * menu當(dāng)前是顯示還是隱藏。只有完全顯示或隱藏menu時才會更改此值,滑動過程中此值無效。
 */
 private boolean isMenuVisible;
 
 /**
 * 用于計算手指滑動的速度。
 */
 private VelocityTracker mVelocityTracker;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 initValues();
 content.setOnTouchListener(this);
 }
 
 /**
 * 初始化一些關(guān)鍵性數(shù)據(jù)。包括獲取屏幕的寬度,給content布局重新設(shè)置寬度,給menu布局重新設(shè)置寬度和偏移距離等。
 */
 private void initValues() {
 WindowManager window = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
 screenWidth = window.getDefaultDisplay().getWidth();
 content = findViewById(R.id.content);
 menu = findViewById(R.id.menu);
 menuParams = (LinearLayout.LayoutParams) menu.getLayoutParams();
 // 將menu的寬度設(shè)置為屏幕寬度減去menuPadding
 menuParams.width = screenWidth - menuPadding;
 // 左邊緣的值賦值為menu寬度的負數(shù)
 leftEdge = -menuParams.width;
 // menu的leftMargin設(shè)置為左邊緣的值,這樣初始化時menu就變?yōu)椴豢梢?
 menuParams.leftMargin = leftEdge;
 // 將content的寬度設(shè)置為屏幕寬度
 content.getLayoutParams().width = screenWidth;
 }
 
 @Override
 public boolean onTouch(View v, MotionEvent event) {
 createVelocityTracker(event);
 switch (event.getAction()) {
 case MotionEvent.ACTION_DOWN:
 // 手指按下時,記錄按下時的橫坐標(biāo)
 xDown = event.getRawX();
 break;
 case MotionEvent.ACTION_MOVE:
 // 手指移動時,對比按下時的橫坐標(biāo),計算出移動的距離,來調(diào)整menu的leftMargin值,從而顯示和隱藏menu
 xMove = event.getRawX();
 int distanceX = (int) (xMove - xDown);
 if (isMenuVisible) {
 menuParams.leftMargin = distanceX;
 } else {
 menuParams.leftMargin = leftEdge + distanceX;
 }
 if (menuParams.leftMargin < leftEdge) {
 menuParams.leftMargin = leftEdge;
 } else if (menuParams.leftMargin > rightEdge) {
 menuParams.leftMargin = rightEdge;
 }
 menu.setLayoutParams(menuParams);
 break;
 case MotionEvent.ACTION_UP:
 // 手指抬起時,進行判斷當(dāng)前手勢的意圖,從而決定是滾動到menu界面,還是滾動到content界面
 xUp = event.getRawX();
 if (wantToShowMenu()) {
 if (shouldScrollToMenu()) {
 scrollToMenu();
 } else {
 scrollToContent();
 }
 } else if (wantToShowContent()) {
 if (shouldScrollToContent()) {
 scrollToContent();
 } else {
 scrollToMenu();
 }
 }
 recycleVelocityTracker();
 break;
 }
 return true;
 }
 
 /**
 * 判斷當(dāng)前手勢的意圖是不是想顯示content。如果手指移動的距離是負數(shù),且當(dāng)前menu是可見的,則認為當(dāng)前手勢是想要顯示content。
 *
 * @return 當(dāng)前手勢想顯示content返回true,否則返回false。
 */
 private boolean wantToShowContent() {
 return xUp - xDown < 0 && isMenuVisible;
 }
 
 /**
 * 判斷當(dāng)前手勢的意圖是不是想顯示menu。如果手指移動的距離是正數(shù),且當(dāng)前menu是不可見的,則認為當(dāng)前手勢是想要顯示menu。
 *
 * @return 當(dāng)前手勢想顯示menu返回true,否則返回false。
 */
 private boolean wantToShowMenu() {
 return xUp - xDown > 0 && !isMenuVisible;
 }
 
 /**
 * 判斷是否應(yīng)該滾動將menu展示出來。如果手指移動距離大于屏幕的1/2,或者手指移動速度大于SNAP_VELOCITY,
 * 就認為應(yīng)該滾動將menu展示出來。
 *
 * @return 如果應(yīng)該滾動將menu展示出來返回true,否則返回false。
 */
 private boolean shouldScrollToMenu() {
 return xUp - xDown > screenWidth / 2 || getScrollVelocity() > SNAP_VELOCITY;
 }
 
 /**
 * 判斷是否應(yīng)該滾動將content展示出來。如果手指移動距離加上menuPadding大于屏幕的1/2,
 * 或者手指移動速度大于SNAP_VELOCITY, 就認為應(yīng)該滾動將content展示出來。
 *
 * @return 如果應(yīng)該滾動將content展示出來返回true,否則返回false。
 */
 private boolean shouldScrollToContent() {
 return xDown - xUp + menuPadding > screenWidth / 2 || getScrollVelocity() > SNAP_VELOCITY;
 }
 
 /**
 * 將屏幕滾動到menu界面,滾動速度設(shè)定為30.
 */
 private void scrollToMenu() {
 new ScrollTask().execute(30);
 }
 
 /**
 * 將屏幕滾動到content界面,滾動速度設(shè)定為-30.
 */
 private void scrollToContent() {
 new ScrollTask().execute(-30);
 }
 
 /**
 * 創(chuàng)建VelocityTracker對象,并將觸摸content界面的滑動事件加入到VelocityTracker當(dāng)中。
 *
 * @param event
 * content界面的滑動事件
 */
 private void createVelocityTracker(MotionEvent event) {
 if (mVelocityTracker == null) {
 mVelocityTracker = VelocityTracker.obtain();
 }
 mVelocityTracker.addMovement(event);
 }
 
 /**
 * 獲取手指在content界面滑動的速度。
 *
 * @return 滑動速度,以每秒鐘移動了多少像素值為單位。
 */
 private int getScrollVelocity() {
 mVelocityTracker.computeCurrentVelocity(1000);
 int velocity = (int) mVelocityTracker.getXVelocity();
 return Math.abs(velocity);
 }
 
 /**
 * 回收VelocityTracker對象。
 */
 private void recycleVelocityTracker() {
 mVelocityTracker.recycle();
 mVelocityTracker = null;
 }
 
 class ScrollTask extends AsyncTask<Integer, Integer, Integer> {
 
 @Override
 protected Integer doInBackground(Integer... speed) {
 int leftMargin = menuParams.leftMargin;
 // 根據(jù)傳入的速度來滾動界面,當(dāng)滾動到達左邊界或右邊界時,跳出循環(huán)。
 while (true) {
 leftMargin = leftMargin + speed[0];
 if (leftMargin > rightEdge) {
 leftMargin = rightEdge;
 break;
 }
 if (leftMargin < leftEdge) {
 leftMargin = leftEdge;
 break;
 }
 publishProgress(leftMargin);
 // 為了要有滾動效果產(chǎn)生,每次循環(huán)使線程睡眠20毫秒,這樣肉眼才能夠看到滾動動畫。
 sleep(20);
 }
 if (speed[0] > 0) {
 isMenuVisible = true;
 } else {
 isMenuVisible = false;
 }
 return leftMargin;
 }
 
 @Override
 protected void onProgressUpdate(Integer... leftMargin) {
 menuParams.leftMargin = leftMargin[0];
 menu.setLayoutParams(menuParams);
 }
 
 @Override
 protected void onPostExecute(Integer leftMargin) {
 menuParams.leftMargin = leftMargin;
 menu.setLayoutParams(menuParams);
 }
 }
 
 /**
 * 使當(dāng)前線程睡眠指定的毫秒數(shù)。
 *
 * @param millis
 * 指定當(dāng)前線程睡眠多久,以毫秒為單位
 */
 private void sleep(long millis) {
 try {
 Thread.sleep(millis);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 }
}

全部的代碼都在這里了,我們可以看到,加上注釋總共才兩百多行的代碼就能實現(xiàn)滑動菜單的特效。下面我來對以上代碼解釋一下,首先初始化的時候調(diào)用initValues方法,在這里面將內(nèi)容布局的寬度設(shè)定為屏幕的寬度,菜單布局的寬度設(shè)定為屏幕的寬度減去menuPadding值,這樣可以保證在菜單布局展示的時候,仍有一部分內(nèi)容布局可以看到。如果不在初始化的時候重定義兩個布局寬度,就會按照layout文件里面聲明的一樣,兩個布局都是fill_parent,這樣就無法實現(xiàn)滑動菜單的效果了。然后將菜單布局的左偏移量設(shè)置為負的菜單布局的寬度,這樣菜單布局就會被完全隱藏,只有內(nèi)容布局會顯示在界面上。

之后給內(nèi)容布局注冊監(jiān)聽事件,這樣當(dāng)手指在內(nèi)容布局上滑動的時候就會觸發(fā)onTouch事件。在onTouch事件里面,根據(jù)手指滑動的距離會改變菜單布局的左偏移量,從而控制菜單布局的顯示和隱藏。當(dāng)手指離開屏幕的時候,會判斷應(yīng)該滑動到菜單布局還是內(nèi)容布局,判斷依據(jù)是根據(jù)手指滑動的距離或者滑動的速度,細節(jié)可以看代碼中的注釋。

最后還是給出AndroidManifest.xml的代碼,都是自動生成的,非常簡單:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 package="com.example.renrenslidemenudemo"
 android:versionCode="1"
 android:versionName="1.0" >
 <uses-sdk
 android:minSdkVersion="8"
 android:targetSdkVersion="8" />
 <application
 android:allowBackup="true"
 android:icon="@drawable/ic_launcher"
 android:label="@string/app_name"
 android:theme="@android:style/Theme.NoTitleBar" >
 <activity
 android:name="com.example.renrenslidemenudemo.MainActivity"
 android:label="@string/app_name" >
 <intent-filter>
 <action android:name="android.intent.action.MAIN" />
 <category android:name="android.intent.category.LAUNCHER" />
 </intent-filter>
 </activity>
 </application>
</manifest>

好了,現(xiàn)在我們運行一下,看一下效果吧,首先是程序剛打開的時候,顯示的是內(nèi)容布局。用手指在界面向右滑動,可以看到菜單布局出現(xiàn)。

Android仿人人客戶端滑動菜單的側(cè)滑菜單效果                 Android仿人人客戶端滑動菜單的側(cè)滑菜單效果
 

而當(dāng)菜單布局完全展示的時候,效果如下圖:

Android仿人人客戶端滑動菜單的側(cè)滑菜單效果
 

今天大家看到了史上最簡單的滑動菜單實現(xiàn)方案,確實是非常簡單。那么有朋友也許會問了,在一個Activity當(dāng)中這樣實現(xiàn)滑動菜單是很簡單,可是如果我的應(yīng)用程序有好多個Activity都需要滑動菜單,每個Activity里都這么實現(xiàn)一遍,也變得復(fù)雜了。沒錯,當(dāng)前的這個解決方案只適用于單個Activity中,如果是想在多個Activity中都實現(xiàn)滑動菜單的效果,請參考我的另一篇文章 Android實現(xiàn)滑動菜單特效的完全解析。

有對雙向滑動菜單感興趣的朋友請轉(zhuǎn)閱 Android實現(xiàn)雙向滑動特效的實例代碼。

好了,今天的講解到此結(jié)束,有疑問的朋友可以在下面留言。

源碼下載,請點擊這里

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。

原文鏈接:https://blog.csdn.net/guolin_blog/article/details/8714621

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 福利一区福利二区 | 免费全看男女拍拍拍的视频 | 午夜理论片日本中文在线 | 欧美xingai| 国产精品欧美亚洲韩国日本 | porno xxxx日本| 午夜理论电影在线观看亚洲 | 鬼吹灯天星术在线高清观看 | 免费看黄色大片 | 亚洲 日韩 国产 制服 在线 | 国产91影院| 日韩一品在线播放视频一品免费 | 天天色综合色 | 高清男的插曲女的 欢迎你老狼 | 国产亚洲人成网站在线观看不卡 | 国产99精品免费视频看6 | 亚洲国产综合自在线另类 | 四虎影音在线 | free性欧洲| 农村老妇1乱69系列小说 | 国自产拍在线天天更新91 | 精品久久久久中文字幕日本 | 国产在线98福利播放视频免费 | 久久免费看少妇级毛片蜜臀 | 美女下面被cao出水 美女污视频 | 亚洲成人在线播放 | 欧美成人乱弄视频 | 亚洲欧美成人综合在线 | 97se亚洲国产综合自在线观看 | 国产精品久久久久这里只有精品 | 色一情一区二区三区四区 | 啪啪模拟器 | 厨房play黄瓜进入 | 天堂伊人网 | 国产精品中文 | 海角社区在线登录 | 亚洲春色综合另类网蜜桃 | m3u8久久国产精品影院 | www.久久精品视频 | 精品国产区一区二区三区在线观看 | 国产国语videosex另类 |