Android UI:篩選條的簡(jiǎn)單實(shí)現(xiàn)

FilterBar

filterbar.gif

這個(gè)篩選條比較常用吧缰猴,做項(xiàng)目遇到過吗购,不過這塊不是我寫的,閑來沒事做個(gè)簡(jiǎn)單封裝腻贰。我覺得重點(diǎn)在這個(gè)箭頭上,畢竟能動(dòng)起來的箭頭更酷炫吁恍,文字顏色切換沒什么好說的。之前看過一個(gè)github上的項(xiàng)目,僅僅用一個(gè)textView冀瓦,然后drawableright屬性使用的是rotatedrawable.setLevel使箭頭轉(zhuǎn)動(dòng)伴奥,很有創(chuàng)意。但我就怕UI把這個(gè)箭頭大小沒弄好翼闽,drawableRight就不好控制箭頭大小了,所以用的是textview+imageView拾徙。

FilterTab

filtertab

布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:gravity="center_horizontal"
    android:layout_height="match_parent">

    <TextView
        android:duplicateParentState="true"
        android:id="@+id/filter_text"
        android:layout_centerVertical="true"
        tools:text="綜合排序"
        style="@style/filterTextStyle" />
    <ImageView
        android:layout_centerVertical="true"
        android:id="@+id/filter_img"
        style="@style/filterImageStyle" />

</RelativeLayout>

textview+image布局很簡(jiǎn)單,樣式寫成style,方便以后修改感局。android:duplicateParentState該屬性可以讓子view狀態(tài)和父view狀態(tài)一樣,字體顏色就可以用selector控制了尼啡。自定義一個(gè)屬性顯示篩選條件的文字,選中和取消選中的時(shí)候執(zhí)行動(dòng)畫询微,然后加了一個(gè)狀態(tài)選中的監(jiān)聽崖瞭。

代碼:

public class FilterTab extends RelativeLayout {

    //旋轉(zhuǎn)動(dòng)畫執(zhí)行時(shí)間
    private static final long DURATION_ROTATE = 200;
    private TextView textFilter;
    private ImageView imgArrow;

    private TabSelectedObervable tabSelectedObervable = new TabSelectedObervable();


    public interface OnTabSelectedChangeListener{
        void onChange(FilterTab filterTab,boolean selected);
    }

    private  class TabSelectedObervable extends Observable<OnTabSelectedChangeListener>{

        public void notifyTabChanged(FilterTab filterTab,boolean selected){
                synchronized(mObservers) {
                    for (int i = mObservers.size() - 1; i >= 0; i--) {
                        mObservers.get(i).onChange(filterTab,selected);
                    }
                }
        }
    }



    public FilterTab(Context context) {
        this(context, null);
    }

    public FilterTab(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public FilterTab(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        LayoutInflater.from(context).inflate(R.layout.filter_tab, this);
        textFilter = (TextView) findViewById(R.id.filter_text);
        imgArrow = (ImageView) findViewById(R.id.filter_img);


        //設(shè)置篩選條件
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.FilterTab);
        String filterText = typedArray.getString(R.styleable.FilterTab_filterText);
        if(!TextUtils.isEmpty(filterText)){
            textFilter.setText(filterText);
        }
        typedArray.recycle();

    }


    /**
     * 設(shè)置篩選標(biāo)簽當(dāng)前篩選條件
     *
     * @param charSequence
     */
    public void setText(CharSequence charSequence) {
        textFilter.setText(charSequence);
    }


    /**
     * 設(shè)置選中狀態(tài)
     *
     * @param selected
     */
    public void setFilterTabSelected(boolean selected) {
        boolean selectedState = isSelected();


        if (selectedState && selected) {//去除無效的狀態(tài)
            return;
        }

        //設(shè)置切換選中狀態(tài)
        setSelected(selected);
        //改變箭頭方向
        rotateArrow(selected);


        //通知觀察者選中狀態(tài)改變
        tabSelectedObervable.notifyTabChanged(this,selected);

    }

    /**
     * 旋轉(zhuǎn)箭頭:選中true,箭頭向上撑毛,取消:false,箭頭向下
     *
     * @param up
     */
    private void rotateArrow(boolean up) {

        ObjectAnimator rotation = ObjectAnimator.ofFloat(imgArrow, "rotation", up?0f:180f, up?180f:360f);
        rotation.setInterpolator(new LinearOutSlowInInterpolator());
        rotation.setDuration(DURATION_ROTATE);
        rotation.start();

    }


    /**
     * 添加狀態(tài)改變的監(jiān)聽
     * @param listener
     */
    public void addTabSelectedChangeListener(OnTabSelectedChangeListener listener){
        tabSelectedObervable.registerObserver(listener);
    }


    /**
     * 移除狀態(tài)改變的監(jiān)聽
     * @param listener
     */
    public void removeTabSelectedChangeListener(OnTabSelectedChangeListener listener){
        tabSelectedObervable.unregisterObserver(listener);
    }

}

FilterBar

單個(gè)篩選條件寫好了书聚,現(xiàn)在要考慮篩選條件之間的相互影響了。比如選中第一個(gè)FilterTab0藻雌,再選第二個(gè)FilterTab1的時(shí)候雌续,F(xiàn)ilterTab0就要取消選中,這點(diǎn)還是需要封裝下的胯杭,不然每次都要處理狀態(tài)很煩驯杜。想了下用一個(gè)線性布局,作為FilterTabs的容器做个,當(dāng)它們填充完畢的時(shí)候就把關(guān)系處理好鸽心。這就涉及每個(gè)FilterTab的狀態(tài)切換了,需要監(jiān)聽居暖,所以我是后來寫FiterBar才王FilterTab加了監(jiān)聽方法的再悼,有時(shí)候真的是水到渠成(想到這個(gè)詞,可能與原意不符膝但,我說的意思就是需要的時(shí)候才自然而然會(huì)去做)。這個(gè)監(jiān)聽事件是用了觀察者模式的谤草,考慮到用戶可能也要加監(jiān)聽跟束,若用set就只能設(shè)置一個(gè)會(huì)覆蓋掉,所以自然而然就寫成addTabSelectedChangeListener了丑孩,跟viewpager.addOnPageChangeListener一樣冀宴,可以設(shè)置多個(gè)。


public class FilterBar extends LinearLayout implements FilterTab.OnTabSelectedChangeListener {
    public FilterBar(Context context) {
        this(context, null);
    }

    public FilterBar(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public FilterBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setOrientation(HORIZONTAL);

    }


    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        syncFilterTabState();
    }

    private void syncFilterTabState() {
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            if (child instanceof FilterTab) {
                ((FilterTab) child).addTabSelectedChangeListener(FilterBar.this);
            }
        }
    }


    private FilterTab lastSelectedTab;

    @Override
    public void onChange(FilterTab filterTab, boolean selected) {
        if (selected) {
            if (lastSelectedTab != null) {
                lastSelectedTab.setFilterTabSelected(false);
            }
            lastSelectedTab = filterTab;
        }else {
            lastSelectedTab = null;
        }

    }
}
到此結(jié)束温学。哦FilterBar繼承的是LinearLayout略贮,所以分割線用showDivider就可以了。

activity_main布局:

[圖片上傳失敗...(image-c827e8-1512974731171)]
filterbar.gif

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"

    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <com.xunevermore.filterbar.FilterBar
        android:id="@+id/filter_bar"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="#fff"
        android:divider="@drawable/divider_filter"
        android:dividerPadding="10dp"
        android:showDividers="middle">

        <com.xunevermore.filterbar.FilterTab
            android:id="@+id/filter_tab0"
            android:layout_width="0dp"
            android:layout_height="50dp"
            android:layout_weight="1"
            android:background="#fff"
            app:filterText="綜合排序" />

        <com.xunevermore.filterbar.FilterTab
            android:id="@+id/filter_tab1"
            android:layout_width="0dp"
            android:layout_height="50dp"
            android:layout_weight="1"
            android:background="#fff"
            app:filterText="產(chǎn)品成分" />

        <com.xunevermore.filterbar.FilterTab
            android:id="@+id/filter_tab2"
            android:layout_width="0dp"
            android:layout_height="50dp"
            android:layout_weight="1"
            android:background="#fff"
            app:filterText="產(chǎn)品色系" />

        <com.xunevermore.filterbar.FilterTab
            android:id="@+id/filter_tab3"
            android:layout_width="0dp"
            android:layout_height="50dp"
            android:layout_weight="1"
            android:background="#fff"
            app:filterText="篩選" />
    </com.xunevermore.filterbar.FilterBar>


</LinearLayout>

github 源碼

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市逃延,隨后出現(xiàn)的幾起案子览妖,更是在濱河造成了極大的恐慌,老刑警劉巖揽祥,帶你破解...
    沈念sama閱讀 217,084評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件讽膏,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡拄丰,警方通過查閱死者的電腦和手機(jī)府树,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來料按,“玉大人奄侠,你說我怎么就攤上這事≡乜螅” “怎么了垄潮?”我有些...
    開封第一講書人閱讀 163,450評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)恢准。 經(jīng)常有香客問我魂挂,道長(zhǎng),這世上最難降的妖魔是什么馁筐? 我笑而不...
    開封第一講書人閱讀 58,322評(píng)論 1 293
  • 正文 為了忘掉前任涂召,我火速辦了婚禮,結(jié)果婚禮上敏沉,老公的妹妹穿的比我還像新娘果正。我一直安慰自己,他們只是感情好盟迟,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評(píng)論 6 390
  • 文/花漫 我一把揭開白布秋泳。 她就那樣靜靜地躺著,像睡著了一般攒菠。 火紅的嫁衣襯著肌膚如雪迫皱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,274評(píng)論 1 300
  • 那天辖众,我揣著相機(jī)與錄音卓起,去河邊找鬼。 笑死凹炸,一個(gè)胖子當(dāng)著我的面吹牛戏阅,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播啤它,決...
    沈念sama閱讀 40,126評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼奕筐,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼舱痘!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起离赫,我...
    開封第一講書人閱讀 38,980評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤芭逝,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后笆怠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體铝耻,經(jīng)...
    沈念sama閱讀 45,414評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評(píng)論 3 334
  • 正文 我和宋清朗相戀三年蹬刷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了瓢捉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,773評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡办成,死狀恐怖泡态,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情迂卢,我是刑警寧澤某弦,帶...
    沈念sama閱讀 35,470評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站而克,受9級(jí)特大地震影響靶壮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜员萍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評(píng)論 3 327
  • 文/蒙蒙 一腾降、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧碎绎,春花似錦螃壤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至日麸,卻和暖如春寄啼,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背代箭。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工辕录, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人梢卸。 一個(gè)月前我還...
    沈念sama閱讀 47,865評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像副女,于是被迫代替她去往敵國(guó)和親蛤高。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 內(nèi)容抽屜菜單ListViewWebViewSwitchButton按鈕點(diǎn)贊按鈕進(jìn)度條TabLayout圖標(biāo)下拉刷新...
    皇小弟閱讀 46,756評(píng)論 22 665
  • 原文鏈接:https://github.com/opendigg/awesome-github-android-u...
    IM魂影閱讀 32,931評(píng)論 6 472
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,095評(píng)論 25 707
  • 終于這一天還是來了,雖然有很多很多的話想和你說戴陡,但是還是不知道去如何開口塞绿,雖然安慰過自己無數(shù)次,也明白早晚你會(huì)...
    花若續(xù)盈閱讀 135評(píng)論 0 0
  • 從頭讀 上一章 目錄 半小時(shí)后恤批,一個(gè)招牌上印著三只皇冠的酒館門口异吻,跌跌撞撞飄來了一頂小黑傘。傘下的兩個(gè)人一邊快步走...
    象牙塔之夢(mèng)閱讀 1,407評(píng)論 5 11