欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android實(shí)現(xiàn)圖片滾動(dòng)和頁(yè)簽控件功能的實(shí)現(xiàn)代碼

 更新時(shí)間:2018年05月11日 09:37:02   作者:guolin  
這篇文章主要介紹了Android實(shí)現(xiàn)圖片滾動(dòng)控件含頁(yè)簽功能的實(shí)現(xiàn)代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,一起跟隨小編過(guò)來(lái)看看吧

首先題外話,今天早上起床的時(shí)候,手滑一下把我的手機(jī)甩了出去,結(jié)果陪伴我兩年半的摩托羅拉里程碑一代就這么安息了,于是我今天決定怒更一記,紀(jì)念我死去的愛機(jī)。

如果你是網(wǎng)購(gòu)達(dá)人,你的手機(jī)上一定少不了淘寶客戶端。關(guān)注特效的人一定都會(huì)發(fā)現(xiàn),淘寶不管是網(wǎng)站還是手機(jī)客戶端,主頁(yè)上都會(huì)有一個(gè)圖片滾動(dòng)播放器,上面展示一些它推薦的商品。這個(gè)幾乎可以用淘寶來(lái)冠名的功能,看起來(lái)還是挺炫的,我們今天就來(lái)實(shí)現(xiàn)一下。

實(shí)現(xiàn)原理其實(shí)還是之前那篇文章Android仿人人客戶端滑動(dòng)菜單的側(cè)滑菜單效果,史上最簡(jiǎn)單的側(cè)滑實(shí)現(xiàn)  ,算是以那個(gè)原理為基礎(chǔ)的另外一個(gè)變種。正所謂一通百通,真正掌握一種方法之后,就可以使用這個(gè)方法變換出各種不通的效果。

今天仍然還是實(shí)現(xiàn)一個(gè)自定義控件,然后我們?cè)谌我釧ctivity的布局文件中引用一下,即可實(shí)現(xiàn)圖片滾動(dòng)器的效果。

在Eclipse中新建一個(gè)Android項(xiàng)目,項(xiàng)目名就叫做SlidingViewSwitcher。

新建一個(gè)類,名叫SlidingSwitcherView,這個(gè)類是繼承自RelativeLayout的,并且實(shí)現(xiàn)了OnTouchListener接口,具體代碼如下:

public class SlidingSwitcherView extends RelativeLayout implements OnTouchListener { 
 /** 
 * 讓菜單滾動(dòng),手指滑動(dòng)需要達(dá)到的速度。 
 */ 
 public static final int SNAP_VELOCITY = 200; 
 /** 
 * SlidingSwitcherView的寬度。 
 */ 
 private int switcherViewWidth; 
 /** 
 * 當(dāng)前顯示的元素的下標(biāo)。 
 */ 
 private int currentItemIndex; 
 /** 
 * 菜單中包含的元素總數(shù)。 
 */ 
 private int itemsCount; 
 /** 
 * 各個(gè)元素的偏移邊界值。 
 */ 
 private int[] borders; 
 /** 
 * 最多可以滑動(dòng)到的左邊緣。值由菜單中包含的元素總數(shù)來(lái)定,marginLeft到達(dá)此值之后,不能再減少。 
 * 
 */ 
 private int leftEdge = 0; 
 /** 
 * 最多可以滑動(dòng)到的右邊緣。值恒為0,marginLeft到達(dá)此值之后,不能再增加。 
 */ 
 private int rightEdge = 0; 
 /** 
 * 記錄手指按下時(shí)的橫坐標(biāo)。 
 */ 
 private float xDown; 
 /** 
 * 記錄手指移動(dòng)時(shí)的橫坐標(biāo)。 
 */ 
 private float xMove; 
 /** 
 * 記錄手機(jī)抬起時(shí)的橫坐標(biāo)。 
 */ 
 private float xUp; 
 /** 
 * 菜單布局。 
 */ 
 private LinearLayout itemsLayout; 
 /** 
 * 標(biāo)簽布局。 
 */ 
 private LinearLayout dotsLayout; 
 /** 
 * 菜單中的第一個(gè)元素。 
 */ 
 private View firstItem; 
 /** 
 * 菜單中第一個(gè)元素的布局,用于改變leftMargin的值,來(lái)決定當(dāng)前顯示的哪一個(gè)元素。 
 */ 
 private MarginLayoutParams firstItemParams; 
 /** 
 * 用于計(jì)算手指滑動(dòng)的速度。 
 */ 
 private VelocityTracker mVelocityTracker; 
 /** 
 * 重寫SlidingSwitcherView的構(gòu)造函數(shù),用于允許在XML中引用當(dāng)前的自定義布局。 
 * 
 * @param context 
 * @param attrs 
 */ 
 public SlidingSwitcherView(Context context, AttributeSet attrs) { 
 super(context, attrs); 
 } 
 /** 
 * 滾動(dòng)到下一個(gè)元素。 
 */ 
 public void scrollToNext() { 
 new ScrollTask().execute(-20); 
 } 
 /** 
 * 滾動(dòng)到上一個(gè)元素。 
 */ 
 public void scrollToPrevious() { 
 new ScrollTask().execute(20); 
 } 
 /** 
 * 在onLayout中重新設(shè)定菜單元素和標(biāo)簽元素的參數(shù)。 
 */ 
 @Override 
 protected void onLayout(boolean changed, int l, int t, int r, int b) { 
 super.onLayout(changed, l, t, r, b); 
 if (changed) { 
  initializeItems(); 
  initializeDots(); 
 } 
 } 
 /** 
 * 初始化菜單元素,為每一個(gè)子元素增加監(jiān)聽事件,并且改變所有子元素的寬度,讓它們等于父元素的寬度。 
 */ 
 private void initializeItems() { 
 switcherViewWidth = getWidth(); 
 itemsLayout = (LinearLayout) getChildAt(0); 
 itemsCount = itemsLayout.getChildCount(); 
 borders = new int[itemsCount]; 
 for (int i = 0; i < itemsCount; i++) { 
  borders[i] = -i * switcherViewWidth; 
  View item = itemsLayout.getChildAt(i); 
  MarginLayoutParams params = (MarginLayoutParams) item.getLayoutParams(); 
  params.width = switcherViewWidth; 
  item.setLayoutParams(params); 
  item.setOnTouchListener(this); 
 } 
 leftEdge = borders[itemsCount - 1]; 
 firstItem = itemsLayout.getChildAt(0); 
 firstItemParams = (MarginLayoutParams) firstItem.getLayoutParams(); 
 } 
 /** 
 * 初始化標(biāo)簽元素。 
 */ 
 private void initializeDots() { 
 dotsLayout = (LinearLayout) getChildAt(1); 
 refreshDotsLayout(); 
 } 
 @Override 
 public boolean onTouch(View v, MotionEvent event) { 
 createVelocityTracker(event); 
 switch (event.getAction()) { 
 case MotionEvent.ACTION_DOWN: 
  // 手指按下時(shí),記錄按下時(shí)的橫坐標(biāo) 
  xDown = event.getRawX(); 
  break; 
 case MotionEvent.ACTION_MOVE: 
  // 手指移動(dòng)時(shí),對(duì)比按下時(shí)的橫坐標(biāo),計(jì)算出移動(dòng)的距離,來(lái)調(diào)整左側(cè)布局的leftMargin值,從而顯示和隱藏左側(cè)布局 
  xMove = event.getRawX(); 
  int distanceX = (int) (xMove - xDown) - (currentItemIndex * switcherViewWidth); 
  firstItemParams.leftMargin = distanceX; 
  if (beAbleToScroll()) { 
  firstItem.setLayoutParams(firstItemParams); 
  } 
  break; 
 case MotionEvent.ACTION_UP: 
  // 手指抬起時(shí),進(jìn)行判斷當(dāng)前手勢(shì)的意圖,從而決定是滾動(dòng)到左側(cè)布局,還是滾動(dòng)到右側(cè)布局 
  xUp = event.getRawX(); 
  if (beAbleToScroll()) { 
  if (wantScrollToPrevious()) { 
   if (shouldScrollToPrevious()) { 
   currentItemIndex--; 
   scrollToPrevious(); 
   refreshDotsLayout(); 
   } else { 
   scrollToNext(); 
   } 
  } else if (wantScrollToNext()) { 
   if (shouldScrollToNext()) { 
   currentItemIndex++; 
   scrollToNext(); 
   refreshDotsLayout(); 
   } else { 
   scrollToPrevious(); 
   } 
  } 
  } 
  recycleVelocityTracker(); 
  break; 
 } 
 return false; 
 } 
 /** 
 * 當(dāng)前是否能夠滾動(dòng),滾動(dòng)到第一個(gè)或最后一個(gè)元素時(shí)將不能再滾動(dòng)。 
 * 
 * @return 當(dāng)前l(fā)eftMargin的值在leftEdge和rightEdge之間返回true,否則返回false。 
 */ 
 private boolean beAbleToScroll() { 
 return firstItemParams.leftMargin < rightEdge && firstItemParams.leftMargin > leftEdge; 
 } 
 /** 
 * 判斷當(dāng)前手勢(shì)的意圖是不是想滾動(dòng)到上一個(gè)菜單元素。如果手指移動(dòng)的距離是正數(shù),則認(rèn)為當(dāng)前手勢(shì)是想要滾動(dòng)到上一個(gè)菜單元素。 
 * 
 * @return 當(dāng)前手勢(shì)想滾動(dòng)到上一個(gè)菜單元素返回true,否則返回false。 
 */ 
 private boolean wantScrollToPrevious() { 
 return xUp - xDown > 0; 
 } 
 /** 
 * 判斷當(dāng)前手勢(shì)的意圖是不是想滾動(dòng)到下一個(gè)菜單元素。如果手指移動(dòng)的距離是負(fù)數(shù),則認(rèn)為當(dāng)前手勢(shì)是想要滾動(dòng)到下一個(gè)菜單元素。 
 * 
 * @return 當(dāng)前手勢(shì)想滾動(dòng)到下一個(gè)菜單元素返回true,否則返回false。 
 */ 
 private boolean wantScrollToNext() { 
 return xUp - xDown < 0; 
 } 
 /** 
 * 判斷是否應(yīng)該滾動(dòng)到下一個(gè)菜單元素。如果手指移動(dòng)距離大于屏幕的1/2,或者手指移動(dòng)速度大于SNAP_VELOCITY, 
 * 就認(rèn)為應(yīng)該滾動(dòng)到下一個(gè)菜單元素。 
 * 
 * @return 如果應(yīng)該滾動(dòng)到下一個(gè)菜單元素返回true,否則返回false。 
 */ 
 private boolean shouldScrollToNext() { 
 return xDown - xUp > switcherViewWidth / 2 || getScrollVelocity() > SNAP_VELOCITY; 
 } 
 /** 
 * 判斷是否應(yīng)該滾動(dòng)到上一個(gè)菜單元素。如果手指移動(dòng)距離大于屏幕的1/2,或者手指移動(dòng)速度大于SNAP_VELOCITY, 
 * 就認(rèn)為應(yīng)該滾動(dòng)到上一個(gè)菜單元素。 
 * 
 * @return 如果應(yīng)該滾動(dòng)到上一個(gè)菜單元素返回true,否則返回false。 
 */ 
 private boolean shouldScrollToPrevious() { 
 return xUp - xDown > switcherViewWidth / 2 || getScrollVelocity() > SNAP_VELOCITY; 
 } 
 /** 
 * 刷新標(biāo)簽元素布局,每次currentItemIndex值改變的時(shí)候都應(yīng)該進(jìn)行刷新。 
 */ 
 private void refreshDotsLayout() { 
 dotsLayout.removeAllViews(); 
 for (int i = 0; i < itemsCount; i++) { 
  LinearLayout.LayoutParams linearParams = new LinearLayout.LayoutParams(0, 
   LayoutParams.FILL_PARENT); 
  linearParams.weight = 1; 
  RelativeLayout relativeLayout = new RelativeLayout(getContext()); 
  ImageView image = new ImageView(getContext()); 
  if (i == currentItemIndex) { 
  image.setBackgroundResource(R.drawable.dot_selected); 
  } else { 
  image.setBackgroundResource(R.drawable.dot_unselected); 
  } 
  RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams( 
   LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 
  relativeParams.addRule(RelativeLayout.CENTER_IN_PARENT); 
  relativeLayout.addView(image, relativeParams); 
  dotsLayout.addView(relativeLayout, linearParams); 
 } 
 } 
 /** 
 * 創(chuàng)建VelocityTracker對(duì)象,并將觸摸事件加入到VelocityTracker當(dāng)中。 
 * 
 * @param event 
 *  右側(cè)布局監(jiān)聽控件的滑動(dòng)事件 
 */ 
 private void createVelocityTracker(MotionEvent event) { 
 if (mVelocityTracker == null) { 
  mVelocityTracker = VelocityTracker.obtain(); 
 } 
 mVelocityTracker.addMovement(event); 
 } 
 /** 
 * 獲取手指在右側(cè)布局的監(jiān)聽View上的滑動(dòng)速度。 
 * 
 * @return 滑動(dòng)速度,以每秒鐘移動(dòng)了多少像素值為單位。 
 */ 
 private int getScrollVelocity() { 
 mVelocityTracker.computeCurrentVelocity(1000); 
 int velocity = (int) mVelocityTracker.getXVelocity(); 
 return Math.abs(velocity); 
 } 
 /** 
 * 回收VelocityTracker對(duì)象。 
 */ 
 private void recycleVelocityTracker() { 
 mVelocityTracker.recycle(); 
 mVelocityTracker = null; 
 } 
 /** 
 * 檢測(cè)菜單滾動(dòng)時(shí),是否有穿越border,border的值都存儲(chǔ)在{@link #borders}中。 
 * 
 * @param leftMargin 
 *  第一個(gè)元素的左偏移值 
 * @param speed 
 *  滾動(dòng)的速度,正數(shù)說(shuō)明向右滾動(dòng),負(fù)數(shù)說(shuō)明向左滾動(dòng)。 
 * @return 穿越任何一個(gè)border了返回true,否則返回false。 
 */ 
 private boolean isCrossBorder(int leftMargin, int speed) { 
 for (int border : borders) { 
  if (speed > 0) { 
  if (leftMargin >= border && leftMargin - speed < border) { 
   return true; 
  } 
  } else { 
  if (leftMargin <= border && leftMargin - speed > border) { 
   return true; 
  } 
  } 
 } 
 return false; 
 } 
 /** 
 * 找到離當(dāng)前的leftMargin最近的一個(gè)border值。 
 * 
 * @param leftMargin 
 *  第一個(gè)元素的左偏移值 
 * @return 離當(dāng)前的leftMargin最近的一個(gè)border值。 
 */ 
 private int findClosestBorder(int leftMargin) { 
 int absLeftMargin = Math.abs(leftMargin); 
 int closestBorder = borders[0]; 
 int closestMargin = Math.abs(Math.abs(closestBorder) - absLeftMargin); 
 for (int border : borders) { 
  int margin = Math.abs(Math.abs(border) - absLeftMargin); 
  if (margin < closestMargin) { 
  closestBorder = border; 
  closestMargin = margin; 
  } 
 } 
 return closestBorder; 
 } 
 class ScrollTask extends AsyncTask<Integer, Integer, Integer> { 
 @Override 
 protected Integer doInBackground(Integer... speed) { 
  int leftMargin = firstItemParams.leftMargin; 
  // 根據(jù)傳入的速度來(lái)滾動(dòng)界面,當(dāng)滾動(dòng)穿越border時(shí),跳出循環(huán)。 
  while (true) { 
  leftMargin = leftMargin + speed[0]; 
  if (isCrossBorder(leftMargin, speed[0])) { 
   leftMargin = findClosestBorder(leftMargin); 
   break; 
  } 
  publishProgress(leftMargin); 
  // 為了要有滾動(dòng)效果產(chǎn)生,每次循環(huán)使線程睡眠10毫秒,這樣肉眼才能夠看到滾動(dòng)動(dòng)畫。 
  sleep(10); 
  } 
  return leftMargin; 
 } 
 @Override 
 protected void onProgressUpdate(Integer... leftMargin) { 
  firstItemParams.leftMargin = leftMargin[0]; 
  firstItem.setLayoutParams(firstItemParams); 
 } 
 @Override 
 protected void onPostExecute(Integer leftMargin) { 
  firstItemParams.leftMargin = leftMargin; 
  firstItem.setLayoutParams(firstItemParams); 
 } 
 } 
 /** 
 * 使當(dāng)前線程睡眠指定的毫秒數(shù)。 
 * 
 * @param millis 
 *  指定當(dāng)前線程睡眠多久,以毫秒為單位 
 */ 
 private void sleep(long millis) { 
 try { 
  Thread.sleep(millis); 
 } catch (InterruptedException e) { 
  e.printStackTrace(); 
 } 
 } 
} 

細(xì)心的朋友可以看出來(lái),我還是重用了很多之前的代碼,這里有幾個(gè)重要點(diǎn)我說(shuō)一下。在onLayout方法里,重定義了各個(gè)包含圖片的控件的大小,然后為每個(gè)包含圖片的控件都注冊(cè)了一個(gè)touch事件監(jiān)聽器。這樣當(dāng)我們滑動(dòng)任何一樣圖片控件的時(shí)候,都會(huì)觸發(fā)onTouch事件,然后通過(guò)改變第一個(gè)圖片控件的leftMargin,去實(shí)現(xiàn)動(dòng)畫效果。之后在onLayout里又動(dòng)態(tài)加入了頁(yè)簽View,有幾個(gè)圖片控件就會(huì)加入幾個(gè)頁(yè)簽,然后根據(jù)currentItemIndex來(lái)決定高亮顯示哪一個(gè)頁(yè)簽。其它也沒什么要特別說(shuō)明的了,更深的理解大家去看代碼和注釋吧。

然后看一下布局文件中如何使用我們自定義的這個(gè)控件,創(chuàng)建或打開activity_main.xml,里面加入如下代碼:

<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" > 
 <com.example.viewswitcher.SlidingSwitcherView 
 android:id="@+id/slidingLayout" 
 android:layout_width="fill_parent" 
 android:layout_height="100dip" > 
 <LinearLayout 
  android:layout_width="fill_parent" 
  android:layout_height="fill_parent" 
  android:orientation="horizontal" > 
  <Button 
  android:layout_width="fill_parent" 
  android:layout_height="fill_parent" 
  android:background="@drawable/image1" /> 
  <Button 
  android:layout_width="fill_parent" 
  android:layout_height="fill_parent" 
  android:background="@drawable/image2" /> 
  <Button 
  android:layout_width="fill_parent" 
  android:layout_height="fill_parent" 
  android:background="@drawable/image3" /> 
  <Button 
  android:layout_width="fill_parent" 
  android:layout_height="fill_parent" 
  android:background="@drawable/image4" /> 
 </LinearLayout> 
 <LinearLayout 
  android:layout_width="60dip" 
  android:layout_height="20dip" 
  android:layout_alignParentBottom="true" 
  android:layout_alignParentRight="true" 
  android:layout_margin="15dip" 
  android:orientation="horizontal" > 
 </LinearLayout> 
 </com.example.viewswitcher.SlidingSwitcherView> 
</LinearLayout> 

 我們可以看到,com.example.viewswitcher.SlidingSwitcherView的根目錄下放置了兩個(gè)LinearLayout。第一個(gè)LinearLayout中要放入需要滾動(dòng)顯示的圖片,這里我們加入了四個(gè)Button,每個(gè)Button都設(shè)置了一張背景圖片。第二個(gè)LinearLayout中不需要加入任何東西,只要控制好大小和位置,標(biāo)簽會(huì)在運(yùn)行的時(shí)候自動(dòng)加入到這個(gè)layout中。

然后創(chuàng)建或打開MainActivity作為主界面,里面沒有加入任何新增的代碼:

public class MainActivity extends Activity { 
 @Override 
 protected void onCreate(Bundle savedInstanceState) { 
 super.onCreate(savedInstanceState); 
 setContentView(R.layout.activity_main); 
 } 
} 

最后是給出AndroidManifest.xml的代碼,也都是自動(dòng)生成的內(nèi)容:

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
 package="com.example.viewswitcher" 
 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.viewswitcher.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)在我們來(lái)看下運(yùn)行效果吧,由于手機(jī)壞了,只能在模擬器上運(yùn)行了。

首先是程序打開的時(shí)候,界面顯示如下:

然后手指在圖片上滑動(dòng),我們可以看到圖片滾動(dòng)的效果:

 

不停的翻頁(yè),頁(yè)簽也會(huì)跟著一起改變,下圖中我們可以看到高亮顯示的點(diǎn)是變換的:

 

恩,對(duì)比一下淘寶客戶端的效果,我覺得我們模仿的還是挺好的。咦,好像少了點(diǎn)什么。。。。。。原來(lái)圖片并不會(huì)自動(dòng)播放。。。。。

沒關(guān)系,我在后面的一篇文章中補(bǔ)充了自動(dòng)播放這個(gè)功能,而且不僅僅是自動(dòng)播放功能喔,請(qǐng)參考 Android使用自定義屬性實(shí)現(xiàn)圖片自動(dòng)播放滾動(dòng)的功能。

今天的文章就到這里了,有問(wèn)題的朋友請(qǐng)?jiān)谙旅媪粞浴?/p>

源碼下載,請(qǐng)點(diǎn)擊這里

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

最新評(píng)論