Android自定義組件(一)

 Android自定義組件(一)瀏覽器

         在原生組件上避免不了覆寫、組合等,以定義本身的組件,也方便之後複用。例如以前工程裏出現了屢次的文件瀏覽器組件。
         嗯~,該怎麼總結呢?
 
1、概述
         自定義組件,大概能夠這麼分吧。1、View或SurfaceView上自繪;2、ViewGroup佈局子類整合;3、不清楚了~,好像也沒什麼好分的==。
 
         本文的工程,我的覺着主要仍是屬性資源的使用吧?工程主要例子介紹以下:
名稱
效果
屬性
Loading動態...的效果組件
loading...的動態效果
定義了以下四屬性:
1)loadImage:load字圖片,reference類型
2)pointImage:小點圖片,reference類型
3)pointCount:小點數目,integer類型
4)msecRate:毫秒級變化速率,integer類型
Title背景移位的效果組件
集合View佈局,造成標題欄。實現了標題項下的背景移動的小效果。
定義了以下屬性:
1)titleLayout:標題欄佈局
2)bgImage:item背景圖片
3)bgLeftMargin:背景初始左邊距
4)animTime:移動動畫時間
ViewPager綁定標題的效果組件
ViewPager綁定標題欄,並實現了標題項下的背景移動的小效果。
效果特徵以下:
1)背景隨ViewPager滾動而同步在標題間滾動
2)點擊標題時,ViewPager程序控制滾動&背景同步
屬性定義以下:
1)tLayout:標題欄佈局
2)bImage:item背景圖片
3)bMargin:背景初始左邊距
ListView增長抽屜的效果組件
ListView增長抽屜的效果組件。抽屜打開的界面只用了一個。
1)listViewId:列表視圖id,reference類型
2)drawerContent:抽屜內容視圖id,reference類型
3)drawerClose:抽屜內容的關閉按鈕id,reference類型
自定義能隱藏更多標題的組件
集合View佈局,造成標題欄。實現超過標題數限制時,自動顯示更多的效果。
初始化時,須要進行以下步驟:
1)設置顯示數限制,默認將爲6。
2)綁定標題內容。爲String[],將直接以TextView顯示==
3)綁定更多操做的視圖id。將本身加載,併爲其設置點擊事件。
4)綁定更多顯示的視圖。應爲已有的ViewGroup。將自動加載超出限制的標題內容(TextView)。更多操做則將控制其顯示或隱藏。
另外,提供刷新內容的方法,用於:1、標題欄內容的從新加載;二,更多顯示內容的從新加載。
自繪實時動態數據線
利用View繪製的實時數據顯示組件?
寫該文檔時才挪進來的了,感受弄得亂亂的。
雙點縮放好像很不正確啊?應該是兩個觸摸點沒弄對,得到的是一個手指頭觸發的兩個點,因此一下放大了。(猜想,總之我是不修了^^)
 
         如下將以「ViewPager擴展組件」爲例了,順便能看下ViewPager組件^^。
 
2、步驟
         帶屬性資源,整合佈局構建自定義組件的步驟~
 
1 )attrs.xml
         定義組件須要用的屬性。不用的話,就至關於一個類爲一個自定義組件,不和這些東西掛鉤。「自定義能隱藏更多標題的組件」便是這樣的,連屬性都沒定義==。
 
ViewPager擴展組件定義的內容:
 
  
  
           
  
  
  1. <!-- TitleViewPager --> 
  2. <declare-styleable name="TitleViewPager"> 
  3.     <attr format="reference" name="tLayout" /> 
  4.     <attr format="reference" name="bImage" /> 
  5.     <attr format="integer" name="bMargin" /> 
  6. </declare-styleable> 
         format類型,參見: Android中attr自定義屬性詳解
 
2 )item.xml
         只要是xml的resources標籤內便可,單獨弄出來呢最好。用如下方式定義一個id,用於View.setId(int id),主要用於相對佈局時,相對於某個id的View什麼的。
 
ViewPager擴展組件定義的內容:
 
  
  
           
  
  
  1. <item name="containerLayout" type="id"/> 
 
3 )建立組件
         其類中引用屬性資源。並看下ViewPager的使用說明吧:OnPageChangeListener接口方法和PagerAdapter適配器內方法的註釋。
 
  
  
           
  
  
  1. public class TitleViewPager extends RelativeLayout implements 
  2.         OnPageChangeListener, View.OnClickListener { 
  3.  
  4.     private Context mContext; // 上下文 
  5.     private LayoutInflater mInflater; // 佈局加載器 
  6.  
  7.     private int titleLayoutId; // 標題欄佈局id 
  8.     private int bgImageResId; // item背景圖片資源id 
  9.     private int bgLeftMargin; // 背景初始左邊距 
  10.  
  11.     private View titleLayout; // 標題欄佈局 
  12.     private ImageView mBgImage; // item背景圖片 
  13.     private ArrayList<View> mItemViews; // 標題項視圖集合 
  14.  
  15.     private ViewPager mViewPager; // ViewPager組件 
  16.     private ArrayList<View> mPageViews; // 頁面視圖集合 
  17.  
  18.     private int prevOffset = -1// 前次偏移值,這裏用了int值像素 
  19.     private int currentIndex; // 當前頁面索引 
  20.     private int previousIndex; // 前次頁面索引 
  21.     private boolean isTitleClicked; // 標題項點擊 
  22.  
  23.     private OnPageChangeListener mOnPageChangeListener; // 頁面變化監聽事件 
  24.  
  25.     // private final int REFRESH_RATE = 20; // 刷新速率20msec 
  26.     // private Scroller mScroller; // 滾動器 
  27.     // private static final Interpolator sInterpolator = new Interpolator() { 
  28.     // public float getInterpolation(float t) { 
  29.     // t -= 1.0f; 
  30.     // return t * t * t + 1.0f; 
  31.     // } 
  32.     // }; 
  33.  
  34.     public TitleViewPager(Context context, AttributeSet attrs) { 
  35.         super(context, attrs); 
  36.  
  37.         mContext = context; 
  38.         mInflater = (LayoutInflater) context 
  39.                 .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
  40.  
  41.         // 得到TypedArray對象 
  42.         TypedArray typedArray = context.obtainStyledAttributes(attrs, 
  43.                 R.styleable.TitleViewPager); 
  44.         // 獲取標題欄佈局id,默認0 
  45.         titleLayoutId = typedArray.getResourceId( 
  46.                 R.styleable.TitleViewPager_tLayout, 0); 
  47.         // 獲取item背景圖片資源id,默認0 
  48.         bgImageResId = typedArray.getResourceId( 
  49.                 R.styleable.TitleViewPager_bImage, 0); 
  50.         // 獲取背景初始左邊距,默認0 
  51.         bgLeftMargin = typedArray.getInt(R.styleable.TitleViewPager_bMargin, 0); 
  52.  
  53.         initLayout(); // 初始化標題欄&ViewPager 
  54.  
  55.         mItemViews = new ArrayList<View>(); 
  56.         mPageViews = new ArrayList<View>(); 
  57.     } 
  58.  
  59.     // 初始化標題欄&ViewPager 
  60.     private void initLayout() { 
  61.         RelativeLayout containerLayout = new RelativeLayout(mContext); // 建立標題欄容器佈局 
  62.         containerLayout.setId(R.id.containerLayout); // 設置標識符 
  63.         LayoutParams containerParams = new LayoutParams( 
  64.                 LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); // 寬度WRAP_CONTENT,高度WRAP_CONTENT 
  65.         containerParams.addRule(RelativeLayout.ALIGN_PARENT_TOP, 
  66.                 RelativeLayout.TRUE); // 貼於頂部 
  67.         containerParams.addRule(RelativeLayout.CENTER_HORIZONTAL, 
  68.                 RelativeLayout.TRUE); // 水平居中 
  69.         addView(containerLayout, containerParams); // 當前佈局增長容器佈局 
  70.         if (0 != bgImageResId) { 
  71.             mBgImage = new ImageView(mContext); // 建立item背景圖片 
  72.             mBgImage.setImageResource(bgImageResId); // 設置item背景圖片 
  73.             LayoutParams p_w_picpathParams = new LayoutParams( 
  74.                     LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); // 寬度WRAP_CONTENT,高度WRAP_CONTENT 
  75.             p_w_picpathParams.addRule(RelativeLayout.CENTER_VERTICAL, 
  76.                     RelativeLayout.TRUE); // 垂直居中 
  77.             p_w_picpathParams.leftMargin = bgLeftMargin; // 左邊距 
  78.             containerLayout.addView(mBgImage, p_w_picpathParams); // 標題欄容器增長標題item背景圖片 
  79.         } 
  80.         if (titleLayoutId != 0) { 
  81.             titleLayout = mInflater.inflate(titleLayoutId, thisfalse); // 得到標題欄佈局 
  82.             LayoutParams titleParams = new LayoutParams( 
  83.                     LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); // 寬度WRAP_CONTENT,高度WRAP_CONTENT 
  84.             titleParams.addRule(RelativeLayout.CENTER_HORIZONTAL, 
  85.                     RelativeLayout.TRUE); // 水平居中 
  86.             titleParams.addRule(RelativeLayout.CENTER_VERTICAL, 
  87.                     RelativeLayout.TRUE); // 垂直居中 
  88.             containerLayout.addView(titleLayout, titleParams); // 標題欄容器增長標題欄佈局 
  89.         } 
  90.         mViewPager = new ViewPager(mContext); // 建立ViewPager 
  91.         mViewPager.setAdapter(new MPagerAdapter()); // 設置ViewPager適配器 
  92.         mViewPager.setOnPageChangeListener(this); // 設置頁面改變的監聽接口 
  93.         LayoutParams viewPagerParams = new LayoutParams( 
  94.                 LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); // 寬度FILL_PARENT,高度FILL_PARENT 
  95.         viewPagerParams.addRule(RelativeLayout.BELOW, containerLayout.getId()); // 佈於標題欄容器下方 
  96.         viewPagerParams.addRule(RelativeLayout.CENTER_HORIZONTAL, 
  97.                 RelativeLayout.TRUE); // 水平居中 
  98.         addView(mViewPager, viewPagerParams); // 當前佈局增長容器ViewPager 
  99.     } 
  100.  
  101.     // 增長一個綁定頁面 
  102.     public void addBindedPage(int pageViewId, int titleItemId) { 
  103.         mPageViews.add(mInflater.inflate(pageViewId, thisfalse)); 
  104.         View item = titleLayout.findViewById(titleItemId); 
  105.         item.setOnClickListener(this); 
  106.         mItemViews.add(item); 
  107.     } 
  108.  
  109.     // 得到頁面數量 
  110.     public int getCount() { 
  111.         return mPageViews.size(); 
  112.     } 
  113.  
  114.     // 初始化頁面(須要在UI加載完後,能夠覆寫onWindowFocusChanged()) 
  115.     public void setPage(int index) { 
  116.         setImagePosition(index); // 設置圖像至標題項位置 
  117.         mViewPager.setCurrentItem(index, false); // 設置ViewPager當前頁面 
  118.     } 
  119.  
  120.     // 設置當前頁面 
  121.     public void setCurrentPage(int index, boolean isAnim) { 
  122.         previousIndex = currentIndex; // 記錄前次頁面索引 
  123.         currentIndex = index; // 設置當前頁面索引 
  124.         mViewPager.setCurrentItem(index, isAnim); // 設置ViewPager當前頁面 
  125.         // Title移動綁定在ViewPager的滾動事件內 
  126.     } 
  127.  
  128.     // 設置圖像至標題項位置 
  129.     private void setImagePosition(int index) { 
  130.         previousIndex = currentIndex; // 記錄前次頁面索引 
  131.         currentIndex = index; // 設置當前頁面索引 
  132.         if (null == mBgImage) { 
  133.             return
  134.         } 
  135.         LayoutParams params = (RelativeLayout.LayoutParams) mBgImage 
  136.                 .getLayoutParams(); // 得到圖片佈局 
  137.         View item = mItemViews.get(index); // 標題項 
  138.         // 注:UI加載完後getLeft()纔有值 
  139.         int targetLeftMargin = (int) (item.getLeft() + item.getWidth() / 2.0 - mBgImage 
  140.                 .getWidth() / 2.0); // 目標左邊距 
  141.         // 位置未變時直接返回,以免屢次setLayoutParams(...) 
  142.         if (params.leftMargin == targetLeftMargin) { 
  143.             return
  144.         } 
  145.         params.leftMargin = targetLeftMargin; 
  146.         mBgImage.setLayoutParams(params); // 使設置生效 
  147.     } 
  148.  
  149.     // 設置圖像移動像素距離 
  150.     private void moveImagePosition(int offset) { 
  151.         if (null == mBgImage) { 
  152.             return
  153.         } 
  154.         LayoutParams params = (RelativeLayout.LayoutParams) mBgImage 
  155.                 .getLayoutParams(); // 得到圖片佈局 
  156.         params.leftMargin += offset; 
  157.         mBgImage.setLayoutParams(params); // 使設置生效 
  158.     } 
  159.  
  160.     /* 
  161.      * 當前頁滾動時調用,不管是程序控制的平滑滾動仍是用戶發起的觸摸滾動。 
  162.      * arg0:第一個頁面當前顯示的位置索引。若是頁面偏移不是0,下一個頁面將會可見。 
  163.      * arg1:表示第二個頁面位置偏移量的比例值,[0, 1)。(右側頁面所佔屏幕百分比) 
  164.      * arg2:表示第二個頁面位置偏移量的像素值。(右側頁面距右邊的像素值) 
  165.      */ 
  166.     @Override 
  167.     public void onPageScrolled(int position, float positionOffset, 
  168.             int positionOffsetPixels) { 
  169.         // 判斷是否不在動畫,用positionOffsetPixels判斷判斷緣由是: 
  170.         // 1)position,在選中了頁面時就會改變,自動動畫時的不能判斷 
  171.         // 2)positionOffset,動畫完變爲0.0,但float很差直接等於判斷 
  172.         // 3)positionOffsetPixels,動畫完變爲0,int型^^ 
  173.         if (positionOffsetPixels == 0) { 
  174.             setImagePosition(position); 
  175.             prevOffset = -1
  176.             isTitleClicked = false
  177.             return
  178.         } 
  179.         // 剛移動時,記錄下該次值 
  180.         if (prevOffset == -1) { 
  181.             prevOffset = positionOffsetPixels; 
  182.             return
  183.         } 
  184.         int pageOffset = positionOffsetPixels - prevOffset; // 頁面偏移距離 
  185.         prevOffset = positionOffsetPixels; 
  186.         if (null != mBgImage) { 
  187.             try { 
  188.                 if (pageOffset < 0) { // 左->右 
  189.                     int prevIndex, nextIndex; 
  190.                     if (isTitleClicked) { 
  191.                         prevIndex = previousIndex; 
  192.                         nextIndex = currentIndex; 
  193.                     } else { 
  194.                         prevIndex = currentIndex; 
  195.                         nextIndex = currentIndex - 1
  196.                     } 
  197.                     // 兩菜單項間的距離 
  198.                     int itemDistance = mItemViews.get(prevIndex).getLeft() 
  199.                             - mItemViews.get(nextIndex).getLeft(); 
  200.                     // 圖片偏移距離 
  201.                     int p_w_picpathOffset = pageOffset * itemDistance 
  202.                             / mViewPager.getWidth(); 
  203.                     // 設置圖像移動像素距離 
  204.                     moveImagePosition(p_w_picpathOffset); 
  205.                 } else if (pageOffset > 0) { // 右->左 
  206.                     int prevIndex, nextIndex; 
  207.                     if (isTitleClicked) { 
  208.                         prevIndex = previousIndex; 
  209.                         nextIndex = currentIndex; 
  210.                     } else { 
  211.                         prevIndex = currentIndex; 
  212.                         nextIndex = currentIndex + 1
  213.                     } 
  214.                     // 兩菜單項間的距離 
  215.                     int itemDistance = mItemViews.get(nextIndex).getLeft() 
  216.                             - mItemViews.get(prevIndex).getLeft(); 
  217.                     // 圖片偏移距離 
  218.                     int p_w_picpathOffset = pageOffset * itemDistance 
  219.                             / mViewPager.getWidth(); 
  220.                     // 設置圖像移動像素距離 
  221.                     moveImagePosition(p_w_picpathOffset); 
  222.                 } 
  223.             } catch (IndexOutOfBoundsException e) { 
  224.                 // 相似在中間左右左右的來回拖拽==,判斷還不夠啊T^T 
  225.                 setImagePosition(currentIndex); 
  226.                 isTitleClicked = false
  227.             } 
  228.         } 
  229.         if (null != mOnPageChangeListener) { 
  230.             mOnPageChangeListener.onPageScrolled(position, positionOffset, 
  231.                     positionOffsetPixels); 
  232.         } 
  233.     } 
  234.  
  235.     /* 
  236.      * 當一個新頁面被選中時被調用。動畫不必定必須完成。 
  237.      * arg0:新選中頁面的位置索引 
  238.      */ 
  239.     @Override 
  240.     public void onPageSelected(int position) { 
  241.         if (null != mOnPageChangeListener) { 
  242.             mOnPageChangeListener.onPageSelected(position); 
  243.         } 
  244.     } 
  245.  
  246.     /* 
  247.      * 滾動狀態改變時調用。用於發現用戶什麼時候開始拖動、頁面什麼時候自動沉降到當前頁(用戶不拖動時)、或者什麼時候徹底中止/空閒。 
  248.      * arg0:新的滾動狀態。SCROLL_STATE_DRAGGING、SCROLL_STATE_SETTLING、SCROLL_STATE_IDLE 
  249.      */ 
  250.     @Override 
  251.     public void onPageScrollStateChanged(int state) { 
  252.         if (state == ViewPager.SCROLL_STATE_DRAGGING) { // 用戶拖動時 
  253.             isTitleClicked = false
  254.         } 
  255.         if (null != mOnPageChangeListener) { 
  256.             mOnPageChangeListener.onPageScrollStateChanged(state); 
  257.         } 
  258.     } 
  259.  
  260.     // 自定義的ViewPager適配器 
  261.     private class MPagerAdapter extends PagerAdapter { 
  262.  
  263.         /* 
  264.          * 移除一個給定位置的頁面。適配器有責任從它的容器中移除視圖,雖然這僅必須確認動做是在finishUpdate()後按時間完成的。 
  265.          * arg0:容器視圖,從中將移除頁面。 
  266.          * arg1:移除的頁面位置 
  267.          * arg2:和instantiateItem(View, int)返回的同樣的對象 
  268.          */ 
  269.         @Override 
  270.         public void destroyItem(View arg0, int arg1, Object arg2) { 
  271.             ((ViewPager) arg0).removeView(mPageViews.get(arg1)); 
  272.         } 
  273.  
  274.         /* 
  275.          * 當顯示的界面完成變化後調用。在這裏,你應當必須確保全部的頁面已經真正的從容器中增長或刪除。 
  276.          * arg0:容器視圖,用於顯示適配器的頁面視圖 
  277.          */ 
  278.         @Override 
  279.         public void finishUpdate(View arg0) { 
  280.         } 
  281.  
  282.         // 返回可用界面的數量 
  283.         @Override 
  284.         public int getCount() { 
  285.             return mPageViews.size(); 
  286.         } 
  287.  
  288.         /* 
  289.          * 建立一個給定位置的界面。適配器有責任給這邊給出的容器增長一個視圖,雖然這僅必須確認動做是在finishUpdate()後按時間完成的。 
  290.          * arg0:容器視圖,在裏面將顯示頁面。 
  291.          * arg1:要被裝載的頁面位置 
  292.          * Object:返回一個展示新畫面的對象。這沒必要須是一個View,也能夠是一些其餘的頁面容器。 
  293.          */ 
  294.         @Override 
  295.         public Object instantiateItem(View arg0, int arg1) { 
  296.             ((ViewPager) arg0).addView(mPageViews.get(arg1), 0); 
  297.             return mPageViews.get(arg1); 
  298.         } 
  299.  
  300.         // 是不是由對象生成的視圖 
  301.         @Override 
  302.         public boolean isViewFromObject(View arg0, Object arg1) { 
  303.             return arg0 == (arg1); 
  304.         } 
  305.  
  306.         // 恢復狀態 
  307.         @Override 
  308.         public void restoreState(Parcelable arg0, ClassLoader arg1) { 
  309.         } 
  310.  
  311.         // 保存狀態,返回序列化對象 
  312.         @Override 
  313.         public Parcelable saveState() { 
  314.             return null
  315.         } 
  316.  
  317.         /* 
  318.          * 當顯示的頁面將要開始變化時調用 
  319.          * arg0:容器視圖,用於顯示適配器的頁面視圖 
  320.          */ 
  321.         @Override 
  322.         public void startUpdate(View arg0) { 
  323.         } 
  324.     } 
  325.  
  326.     @Override 
  327.     public void onClick(View v) { 
  328.         int size = mItemViews.size(); // 大小 
  329.         for (int i = 0; i < size; i++) { 
  330.             if (mItemViews.get(i).getId() == v.getId()) { 
  331.                 isTitleClicked = true
  332.                 setCurrentPage(i, true); 
  333.                 break
  334.             } 
  335.         } 
  336.     } 
  337.  
  338.     // 得到標題項視圖集合 
  339.     public ArrayList<View> getItemViews() { 
  340.         return mItemViews; 
  341.     } 
  342.  
  343.     // 得到 頁面視圖集合 
  344.     public ArrayList<View> getPageViews() { 
  345.         return mPageViews; 
  346.     } 
  347.  
  348.     // 設置頁面變化監聽事件 
  349.     public void setOnPageChangeListener(OnPageChangeListener listener) { 
  350.         mOnPageChangeListener = listener; 
  351.     } 
  352.  
 
 
         附件工程,見(二)。
相關文章
相關標籤/搜索