底部導航漸層效果-----viewpager&PorterDuffXfermode,漸層-----viewpager
實現這個功能主要涉及的知識點有
ViewPager關於ViewPager需要注意的知識主要是OnPageChangeListener,該介面的三個方法如下
public abstract void onPageScrollStateChanged (int state)public abstract void onPageScrolled (int position, float positionOffset, int positionOffsetPixels)public abstract void onPageSelected (int position)
第一個方法onPageScrollStateChanged 中的參數state,有三個可取的值
public static final int SCROLL_STATE_DRAGGINGConstant Value: 1 (0x00000001)public static final int SCROLL_STATE_IDLEConstant Value: 0 (0x00000000)public static final int SCROLL_STATE_SETTLINGConstant Value: 2 (0x00000002)
SCROLL_STATE_DRAGGING:手指按在viewpager上滑動時
SCROLL_STATE_SETTLING:手指鬆開後,viewpager自動滑動期間
SCROLL_STATE_IDLE:viewpager滑動進入了某個page。
如果你在onPageScrollStateChanged 中輸出state的值,你會發現每次都是按順序列印出“1---2----0”
第二個方法onPageScrolled的三個參數position:滑動時,螢幕左側顯示的第一個page
positionOffset:滑動比例,值的範圍為[0, 1),手指往左滑動,該值遞增,反之遞減
positionOffsetPixels:滑動距離,和螢幕有關,手指往左滑動,該值遞增,反之遞減
我們經常需要檢查viewpager的滑動方向並作出一些操作,這時你只需要通過position和positionOffset兩個值即可實現該功能。
第三個方法onPageSelected的三個參數position:當前選擇的page序號
該方法被調用的時間比較特別,在上面的第一個方法中的“1---2----0”中的2執行之後,onPageSelected就執行,然後執行“1---2----0”中的0。就是手指鬆開螢幕之後,onPageSelected被執行。
以下在代碼中自己重寫的一個OnPageChangeListener
/** * @author Quinn * @date 2015-2-28 */public class MainPagerChangeListener implements OnPageChangeListener{public interface PagerCallback{public void changePageColor(int index, int offset);}private PagerCallback callback;public MainPagerChangeListener(MainActivity mainActivity){this.callback = (PagerCallback)mainActivity;}//順序為1-2-0@Overridepublic void onPageScrollStateChanged(int state) {}@Overridepublic void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {if(positionOffset != 0.0f){callback.changePageColor(position+1, (int)(positionOffset * 255));callback.changePageColor(position, (int)((1-positionOffset) * 255));}}@Overridepublic void onPageSelected(int position) {}}
首先我們留一個回調介面PagerCallback,然後在onPageScrolled中執行操作。可以根據position和positionOffset兩個值,對兩個方向的page進行不同的操作。我們這裡進行的操作是改變表徵圖的顏色。
PorterDuffXfermode先看以下這幅圖
的底部圖案,其原型是一個灰色的圖案,在滑動時,會發生色彩坡形,那麼怎樣使一張圖片產生這樣的效果呢?其原理是利用PorterDuffXfermode!先看以下這張圖片
上述16個圖,我們看第二排的第三個,黃色部分代表Dst,藍色部分代表Src,將Dst覆蓋在Src之上,選擇"DstIn"模式,就可以合成上述第二排第三張圖片。那麼,如果Src是一個灰色的圖片(圖片部分是透明的,像上面的四個表徵圖),Dst是一個綠色的矩形,其大小和圖片一致。然後將綠色的矩形覆蓋在圖片之上,選擇“DstIn”模式,就能達到將圖片設定成綠色的效果。在這個基礎上,要對圖片進行色彩坡形,只需在viewpager滑動時修改上述Dst矩形的顏色透明度即可。實現代碼可以在文章末尾下載源碼。部落客要記錄實現思路和細節,貼出代碼感覺太冗長了。自訂視圖自訂視圖,一般按以下步驟進行
- 自訂屬性
- 擷取屬性
- 重寫onMeasure
- 重寫onDraw
我們在自訂底部帶文字的表徵圖,自訂屬性如下:
路徑:XMPP\res\values\attrs.xml
<?xml version="1.0" encoding="utf-8"?><resources> <declare-styleable name="FooterTextIcon"> <attr name="iconSrc" format="reference" /> <attr name="color" format="color"/> <attr name="text" format="string"/> <attr name="textSize" format="dimension"/> </declare-styleable></resources>
這些自訂屬性的使用方式如下
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:FooterIcon="http://schemas.android.com/apk/res/com.quinn.xmpp" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.quinn.xmpp.ui.main.MainActivity" >//省略,,,,//,,,//,,, <com.quinn.xmpp.ui.widget.FooterTextIcon android:id="@+id/chattingIcon" android:layout_width="0dip" android:layout_height="match_parent" android:layout_weight="1" FooterIcon:iconSrc="@drawable/ic_action_chat" FooterIcon:text="聊天" FooterIcon:textSize="12sp" android:padding="5dip" FooterIcon:color="#ff181818" />//省略,,,,//,,,//,,,</LinearLayout>
在使用自訂屬性時,需要在使用這些自訂屬性的布局檔案中引入一個命名空間,比如上述代碼的第三行,它的格式是:
xmlns:自己起一個名字="http://schemas.android.com/apk/res/應用的包名"
注意,上面代碼的最後一部分是應用的包名,而不是某個Activity的包名或者自訂群組件對應Java檔案的包名
前面自訂屬性的attrs.xml中,可以自訂的屬性類型(對應上述的format)有以下幾種reference、string、color、dimension、boolean、integer、float、fraction、enum、flag主要講講其中比較常用而且容易混淆的四個reference的值必須是"@drawable/xxxxxx"比如上面的
FooterIcon:iconSrc="@drawable/ic_action_chat"
而string,color,dimension的值可以直接寫某個值,也可以是引用於資源檔string.xml,color.xml,dimens.xml比如
FooterIcon:text="聊天" FooterIcon:textSize="12sp" android:padding="5dip" FooterIcon:color="#ff181818"</span>
也可以寫成
FooterIcon:text="@string/xxxxx" FooterIcon:textSize="@dimen/xxxx" android:padding="@dimen/xxxx" FooterIcon:color="@color/xxxx" />
然後,我們需要在一個地方使用這些屬性的值,就是在我們的自訂群組件的類檔案中。如下:
public class FooterTextIcon extends View {//四個屬性private String text;private int themeColor;private int textSize;private int iconRid;//、、、/** * @param context */public FooterTextIcon(Context context) {this(context, null);}public FooterTextIcon(Context context, AttributeSet attrs) {this(context, attrs, 0);}/** * @param context * @param attrs * @param defStyleAttr */public FooterTextIcon(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.FooterTextIcon);iconRid = a.getResourceId(R.styleable.FooterTextIcon_iconSrc, -1);text = a.getString(R.styleable.FooterTextIcon_text);textSize = (int) a.getDimension(R.styleable.FooterTextIcon_textSize, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 12,getResources().getDisplayMetrics()));themeColor = a.getColor(R.styleable.FooterTextIcon_color, Color.parseColor(DEFAULT_CHOSEN_COLOR));a.recycle(); //,,,} //,,省略,,}如上,我們在建構函式中,通過一個TypeArray對象擷取各種類型的屬性,並且最後調用TypeArray的recycle函數回收記憶體。一般我們將這些代碼放在有三個參數的構造方法中執行,而又一個參數的構造方法直接用this指標調用有兩個參數的構造方法,同理,兩個的調用三個的。
關於自訂群組件的知識可以參考另外兩篇部落格android自訂View-------滑動按鈕
android自訂View-------為什麼重寫onMeasure()以及怎麼重寫
該功能目前應用於我的XMPP項目 https://github.com/Leaking/xmppIM
後續堅持把寫這個開源項目使用到的知識都記錄在部落格裡。