Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 自定義解析之 HorizontalScrollView 打造再多圖片(控件)也不怕 OOM 的橫向滑動效果

Android 自定義解析之 HorizontalScrollView 打造再多圖片(控件)也不怕 OOM 的橫向滑動效果

編輯:關於Android編程

看下最後的效果圖:

\

為了增加一定的趣味,做了一個類似上面的相冊效果,支持拖動時自動變化,和點擊變化~~是不是很贊~

1、首先看布局文件:

 

[html]view plaincopy   在CODE上查看代碼片派生到我的代碼片    
  1. xmlns:tools="http://schemas.android.com/tools"
  2. android:layout_width="match_parent"
  3. android:layout_height="match_parent"
  4. android:background="@android:color/white"
  5. android:orientation="vertical">
  6.  
  7. <framelayout
  8. android:layout_height="0dp"
  9. android:layout_weight="1">
  10.  
  11. android:id="@+id/id_content"
  12. android:layout_width="fill_parent"
  13. android:layout_height="fill_parent"
  14. android:layout_gravity="center"
  15. android:layout_margin="10dp"
  16. android:scaleType="centerCrop"
  17. android:src="@drawable/ic_launcher"/>
  18.  
  19.  
  20. android:id="@+id/id_horizontalScrollView"
  21. android:layout_width="wrap_content"
  22. android:layout_height="150dp"
  23. android:layout_gravity="bottom"
  24. android:background="@android:color/white"
  25. android:scrollbars="none">
  26.  
  27. android:id="@+id/id_gallery"
  28. android:layout_width="wrap_content"
  29. android:layout_height="wrap_content"
  30. android:layout_gravity="center_vertical"
  31. android:orientation="horizontal">
  32.  
  33.  
  34.  
  35.   沒任何變化,除了把類名改成了我們自定義的類~

    2、為了和國際接軌,我們也搞個Adapter,類似BaseAdapter

     

    [java]view plaincopy   在CODE上查看代碼片派生到我的代碼片    
    1. packagecom.example.zhy_horizontalscrollview;
    2.  
    3. importjava.util.List;
    4.  
    5. importandroid.content.Context;
    6. importandroid.view.LayoutInflater;
    7. importandroid.view.View;
    8. importandroid.view.ViewGroup;
    9. importandroid.widget.BaseAdapter;
    10. importandroid.widget.ImageView;
    11. importandroid.widget.TextView;
    12.  
    13. publicclassHorizontalScrollViewAdapter
    14. {
    15.  
    16. privateContextmContext;
    17. privateLayoutInflatermInflater;
    18. privateListmDatas;
    19.  
    20. publicHorizontalScrollViewAdapter(Contextcontext,ListmDatas)
    21. {
    22. this.mContext=context;
    23. mInflater=LayoutInflater.from(context);
    24. this.mDatas=mDatas;
    25. }
    26.  
    27. publicintgetCount()
    28. {
    29. returnmDatas.size();
    30. }
    31.  
    32. publicObjectgetItem(intposition)
    33. {
    34. returnmDatas.get(position);
    35. }
    36.  
    37. publiclonggetItemId(intposition)
    38. {
    39. returnposition;
    40. }
    41.  
    42. publicViewgetView(intposition,ViewconvertView,ViewGroupparent)
    43. {
    44. ViewHolderviewHolder=null;
    45. if(convertView==null)
    46. {
    47. viewHolder=newViewHolder();
    48. convertView=mInflater.inflate(
    49. R.layout.activity_index_gallery_item,parent,false);
    50. viewHolder.mImg=(ImageView)convertView
    51. .findViewById(R.id.id_index_gallery_item_image);
    52. viewHolder.mText=(TextView)convertView
    53. .findViewById(R.id.id_index_gallery_item_text);
    54.  
    55. convertView.setTag(viewHolder);
    56. }else
    57. {
    58. viewHolder=(ViewHolder)convertView.getTag();
    59. }
    60. viewHolder.mImg.setImageResource(mDatas.get(position));
    61. viewHolder.mText.setText("someinfo");
    62.  
    63. returnconvertView;
    64. }
    65.  
    66. privateclassViewHolder
    67. {
    68. ImageViewmImg;
    69. TextViewmText;
    70. }
    71.  
    72. }  
      3、下面先看用法:

       

       

      [java]view plaincopy   在CODE上查看代碼片派生到我的代碼片    
      1. packagecom.example.zhy_horizontalscrollview;
      2.  
      3. importjava.util.ArrayList;
      4. importjava.util.Arrays;
      5. importjava.util.List;
      6.  
      7. importandroid.app.Activity;
      8. importandroid.graphics.Color;
      9. importandroid.os.Bundle;
      10. importandroid.view.View;
      11. importandroid.view.Window;
      12. importandroid.widget.ImageView;
      13.  
      14. importcom.example.zhy_horizontalscrollview.MyHorizontalScrollView.CurrentImageChangeListener;
      15. importcom.example.zhy_horizontalscrollview.MyHorizontalScrollView.OnItemClickListener;
      16.  
      17. publicclassMainActivityextendsActivity
      18. {
      19.  
      20. privateMyHorizontalScrollViewmHorizontalScrollView;
      21. privateHorizontalScrollViewAdaptermAdapter;
      22. privateImageViewmImg;
      23. privateListmDatas=newArrayList(Arrays.asList(
      24. R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,
      25. R.drawable.e,R.drawable.f,R.drawable.g,R.drawable.h,
      26. R.drawable.l));
      27.  
      28. @Override
      29. protectedvoidonCreate(BundlesavedInstanceState)
      30. {
      31. super.onCreate(savedInstanceState);
      32. requestWindowFeature(Window.FEATURE_NO_TITLE);
      33. setContentView(R.layout.activity_main);
      34.  
      35. mImg=(ImageView)findViewById(R.id.id_content);
      36.  
      37. mHorizontalScrollView=(MyHorizontalScrollView)findViewById(R.id.id_horizontalScrollView);
      38. mAdapter=newHorizontalScrollViewAdapter(this,mDatas);
      39. //添加滾動回調
      40. mHorizontalScrollView
      41. .setCurrentImageChangeListener(newCurrentImageChangeListener()
      42. {
      43. @Override
      44. publicvoidonCurrentImgChanged(intposition,
      45. ViewviewIndicator)
      46. {
      47. mImg.setImageResource(mDatas.get(position));
      48. viewIndicator.setBackgroundColor(Color
      49. .parseColor("#AA024DA4"));
      50. }
      51. });
      52. //添加點擊回調
      53. mHorizontalScrollView.setOnItemClickListener(newOnItemClickListener()
      54. {
      55.  
      56. @Override
      57. publicvoidonClick(Viewview,intposition)
      58. {
      59. mImg.setImageResource(mDatas.get(position));
      60. view.setBackgroundColor(Color.parseColor("#AA024DA4"));
      61. }
      62. });
      63. //設置適配器
      64. mHorizontalScrollView.initDatas(mAdapter);
      65. }
      66.  
      67. }  
        用起來是不是有點像ListView,初始化數據適配器,然後設置數據適配器,然後就是設置各種回調~~

         

        如果僅僅是一堆圖片展示,類似商品切換,更見簡單,就不需要設置滾動監聽和點擊監聽了~

        4、最後看自定義的MyHorizontalScrollView類

         

        [java]view plaincopy   在CODE上查看代碼片派生到我的代碼片    
        1. packagecom.example.zhy_horizontalscrollview;
        2.  
        3. importjava.util.HashMap;
        4. importjava.util.Map;
        5.  
        6. importandroid.content.Context;
        7. importandroid.graphics.Color;
        8. importandroid.util.AttributeSet;
        9. importandroid.util.DisplayMetrics;
        10. importandroid.util.Log;
        11. importandroid.view.MotionEvent;
        12. importandroid.view.View;
        13. importandroid.view.View.OnClickListener;
        14. importandroid.view.WindowManager;
        15. importandroid.widget.HorizontalScrollView;
        16. importandroid.widget.LinearLayout;
        17.  
        18. publicclassMyHorizontalScrollViewextendsHorizontalScrollViewimplements
        19. OnClickListener
        20. {
        21.  
        22. /**
        23. *圖片滾動時的回調接口
        24. *
        25. *@authorzhy
        26. *
        27. */
        28. publicinterfaceCurrentImageChangeListener
        29. {
        30. voidonCurrentImgChanged(intposition,ViewviewIndicator);
        31. }
        32.  
        33. /**
        34. *條目點擊時的回調
        35. *
        36. *@authorzhy
        37. *
        38. */
        39. publicinterfaceOnItemClickListener
        40. {
        41. voidonClick(Viewview,intpos);
        42. }
        43.  
        44. privateCurrentImageChangeListenermListener;
        45.  
        46. privateOnItemClickListenermOnClickListener;
        47.  
        48. privatestaticfinalStringTAG="MyHorizontalScrollView";
        49.  
        50. /**
        51. *HorizontalListView中的LinearLayout
        52. */
        53. privateLinearLayoutmContainer;
        54.  
        55. /**
        56. *子元素的寬度
        57. */
        58. privateintmChildWidth;
        59. /**
        60. *子元素的高度
        61. */
        62. privateintmChildHeight;
        63. /**
        64. *當前最後一張圖片的index
        65. */
        66. privateintmCurrentIndex;
        67. /**
        68. *當前第一張圖片的下標
        69. */
        70. privateintmFristIndex;
        71. /**
        72. *當前第一個View
        73. */
        74. privateViewmFirstView;
        75. /**
        76. *數據適配器
        77. */
        78. privateHorizontalScrollViewAdaptermAdapter;
        79. /**
        80. *每屏幕最多顯示的個數
        81. */
        82. privateintmCountOneScreen;
        83. /**
        84. *屏幕的寬度
        85. */
        86. privateintmScreenWitdh;
        87.  
        88.  
        89. /**
        90. *保存View與位置的鍵值對
        91. */
        92. privateMapmViewPos=newHashMap();
        93.  
        94. publicMyHorizontalScrollView(Contextcontext,AttributeSetattrs)
        95. {
        96. super(context,attrs);
        97. //獲得屏幕寬度
        98. WindowManagerwm=(WindowManager)context
        99. .getSystemService(Context.WINDOW_SERVICE);
        100. DisplayMetricsoutMetrics=newDisplayMetrics();
        101. wm.getDefaultDisplay().getMetrics(outMetrics);
        102. mScreenWitdh=outMetrics.widthPixels;
        103. }
        104.  
        105. @Override
        106. protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec)
        107. {
        108. super.onMeasure(widthMeasureSpec,heightMeasureSpec);
        109. mContainer=(LinearLayout)getChildAt(0);
        110. }
        111.  
        112. /**
        113. *加載下一張圖片
        114. */
        115. protectedvoidloadNextImg()
        116. {
        117. //數組邊界值計算
        118. if(mCurrentIndex==mAdapter.getCount()-1)
        119. {
        120. return;
        121. }
        122. //移除第一張圖片,且將水平滾動位置置0
        123. scrollTo(0,0);
        124. mViewPos.remove(mContainer.getChildAt(0));
        125. mContainer.removeViewAt(0);
        126.  
        127. //獲取下一張圖片,並且設置onclick事件,且加入容器中
        128. Viewview=mAdapter.getView(++mCurrentIndex,null,mContainer);
        129. view.setOnClickListener(this);
        130. mContainer.addView(view);
        131. mViewPos.put(view,mCurrentIndex);
        132.  
        133. //當前第一張圖片小標
        134. mFristIndex++;
        135. //如果設置了滾動監聽則觸發
        136. if(mListener!=null)
        137. {
        138. notifyCurrentImgChanged();
        139. }
        140.  
        141. }
        142. /**
        143. *加載前一張圖片
        144. */
        145. protectedvoidloadPreImg()
        146. {
        147. //如果當前已經是第一張,則返回
        148. if(mFristIndex==0)
        149. return;
        150. //獲得當前應該顯示為第一張圖片的下標
        151. intindex=mCurrentIndex-mCountOneScreen;
        152. if(index>=0)
        153. {
        154. //mContainer=(LinearLayout)getChildAt(0);
        155. //移除最後一張
        156. intoldViewPos=mContainer.getChildCount()-1;
        157. mViewPos.remove(mContainer.getChildAt(oldViewPos));
        158. mContainer.removeViewAt(oldViewPos);
        159.  
        160. //將此View放入第一個位置
        161. Viewview=mAdapter.getView(index,null,mContainer);
        162. mViewPos.put(view,index);
        163. mContainer.addView(view,0);
        164. view.setOnClickListener(this);
        165. //水平滾動位置向左移動view的寬度個像素
        166. scrollTo(mChildWidth,0);
        167. //當前位置--,當前第一個顯示的下標--
        168. mCurrentIndex--;
        169. mFristIndex--;
        170. //回調
        171. if(mListener!=null)
        172. {
        173. notifyCurrentImgChanged();
        174.  
        175. }
        176. }
        177. }
        178.  
        179. /**
        180. *滑動時的回調
        181. */
        182. publicvoidnotifyCurrentImgChanged()
        183. {
        184. //先清除所有的背景色,點擊時會設置為藍色
        185. for(inti=0;i {
        186. mContainer.getChildAt(i).setBackgroundColor(Color.WHITE);
        187. }
        188.  
        189. mListener.onCurrentImgChanged(mFristIndex,mContainer.getChildAt(0));
        190.  
        191. }
        192.  
        193. /**
        194. *初始化數據,設置數據適配器
        195. *
        196. *@parammAdapter
        197. */
        198. publicvoidinitDatas(HorizontalScrollViewAdaptermAdapter)
        199. {
        200. this.mAdapter=mAdapter;
        201. mContainer=(LinearLayout)getChildAt(0);
        202. //獲得適配器中第一個View
        203. finalViewview=mAdapter.getView(0,null,mContainer);
        204. mContainer.addView(view);
        205.  
        206. //強制計算當前View的寬和高
        207. if(mChildWidth==0&&mChildHeight==0)
        208. {
        209. intw=View.MeasureSpec.makeMeasureSpec(0,
        210. View.MeasureSpec.UNSPECIFIED);
        211. inth=View.MeasureSpec.makeMeasureSpec(0,
        212. View.MeasureSpec.UNSPECIFIED);
        213. view.measure(w,h);
        214. mChildHeight=view.getMeasuredHeight();
        215. mChildWidth=view.getMeasuredWidth();
        216. Log.e(TAG,view.getMeasuredWidth()+","+view.getMeasuredHeight());
        217. mChildHeight=view.getMeasuredHeight();
        218. //計算每次加載多少個View
        219. mCountOneScreen=mScreenWitdh/mChildWidth+2;
        220.  
        221. Log.e(TAG,"mCountOneScreen="+mCountOneScreen
        222. +",mChildWidth="+mChildWidth);
        223.  
        224.  
        225. }
        226. //初始化第一屏幕的元素
        227. initFirstScreenChildren(mCountOneScreen);
        228. }
        229.  
        230. /**
        231. *加載第一屏的View
        232. *
        233. *@parammCountOneScreen
        234. */
        235. publicvoidinitFirstScreenChildren(intmCountOneScreen)
        236. {
        237. mContainer=(LinearLayout)getChildAt(0);
        238. mContainer.removeAllViews();
        239. mViewPos.clear();
        240.  
        241. for(inti=0;i {
        242. Viewview=mAdapter.getView(i,null,mContainer);
        243. view.setOnClickListener(this);
        244. mContainer.addView(view);
        245. mViewPos.put(view,i);
        246. mCurrentIndex=i;
        247. }
        248.  
        249. if(mListener!=null)
        250. {
        251. notifyCurrentImgChanged();
        252. }
        253.  
        254. }
        255.  
        256. @Override
        257. publicbooleanonTouchEvent(MotionEventev)
        258. {
        259. switch(ev.getAction())
        260. {
        261. caseMotionEvent.ACTION_MOVE:
        262. //Log.e(TAG,getScrollX()+"");
        263.  
        264. intscrollX=getScrollX();
        265. //如果當前scrollX為view的寬度,加載下一張,移除第一張
        266. if(scrollX>=mChildWidth)
        267. {
        268. loadNextImg();
        269. }
        270. //如果當前scrollX=0,往前設置一張,移除最後一張
        271. if(scrollX==0)
        272. {
        273. loadPreImg();
        274. }
        275. break;
        276. }
        277. returnsuper.onTouchEvent(ev);
        278. }
        279.  
        280. @Override
        281. publicvoidonClick(Viewv)
        282. {
        283. if(mOnClickListener!=null)
        284. {
        285. for(inti=0;i {
        286. mContainer.getChildAt(i).setBackgroundColor(Color.WHITE);
        287. }
        288. mOnClickListener.onClick(v,mViewPos.get(v));
        289. }
        290. }
        291.  
        292. publicvoidsetOnItemClickListener(OnItemClickListenermOnClickListener)
        293. {
        294. this.mOnClickListener=mOnClickListener;
        295. }
        296.  
        297. publicvoidsetCurrentImageChangeListener(
        298. CurrentImageChangeListenermListener)
        299. {
        300. this.mListener=mListener;
        301. }
        302.  
        303. }  

          首先,加載第一個Item,根據item的寬計算當前屏幕可以加載多少張圖片,然後初始化第一屏的圖片,接下來就是從寫onTouchEvent,在其中監聽用戶的ACTION_MOVE,然後根據移動的距離加載前一張或者後一張,同時動態移除不可見的View,回收內存~~~~

          代碼中有個Map專門存儲View和posion的,主要是為了給點擊回調提供當前的View的位置,有點類似:Android 自定義 ViewPager 打造千變萬化的圖片切換效果裡面的Map的巧妙用法~~

          是不是完全實現了ViewPager和HorizontalScrollView的合體~~~HorizontalScrollView的效果,ViewPager的特性~~~~

          最後貼一下旋轉屏幕後的效果圖:

          \

          可以看出,不僅是做相冊,還是圖片輪播想過都是剛剛的!

             
  36. </framelayout
<framelayout
    1. </framelayout<framelayout
      1. </framelayout
          1. 上一頁:
          2. 下一頁:
          熱門文章
          閱讀排行版
          Copyright © Android教程網 All Rights Reserved