Android解析自定义属性的XML实现底部导航栏TabSelectedView,实现灵活的配置扩展

来源:互联网 发布:淘宝网店装修策略 编辑:程序博客网 时间:2024/05/21 07:06

自定义View底部导航栏需要实现常用的功能

如同所有的底部栏

1:界面达到自定义

2:跳转达到自定义

3:导航数量达到可配置

这三个功能要求我们地步导航栏必须可拓展可配置

先上图看一下我们怎么实现可配置的底部导航栏




由于我现在开发的场景要求下面tab经常更换数量不一定,如果我们使用常规的布局LinearLayout+RadioGroup每次更换的时候都需要改动大量基类的代码

所以从系统应用Settings那边收到启发通过xml去配置我们的底部tab选项


看一下底部Tab选项的XML配置文件


<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2014 The Android Open Source Project     Licensed under the Apache License, Version 2.0 (the "License");     you may not use this file except in compliance with the License.     You may obtain a copy of the License at          http://www.apache.org/licenses/LICENSE-2.0     Unless required by applicable law or agreed to in writing, software     distributed under the License is distributed on an "AS IS" BASIS,     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.     See the License for the specific language governing permissions and     limitations under the License.--><dashboard-categories xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:SiriusPreferenceHeader="http://schemas.android.com/apk/res-auto">    <dashboard-category>        <dashboard-tile            SiriusPreferenceHeader:clickTag="@string/app_power"            SiriusPreferenceHeader:icon="@drawable/icon_remote_control"            SiriusPreferenceHeader:title="@string/app_power">            <intent                android:targetClass="com.mediatek.systemupdate.MainEntry"                android:targetPackage="com.mediatek.systemupdate" />        </dashboard-tile>        <dashboard-tile            SiriusPreferenceHeader:clickTag="@string/app_service"            SiriusPreferenceHeader:icon="@drawable/icon_service"            SiriusPreferenceHeader:title="@string/app_service">            <intent                android:action="android.intent.action.MAIN"                android:targetClass="com.mediatek.systemupdate.MainEntry"                android:targetPackage="com.mediatek.systemupdate" />        </dashboard-tile>        <dashboard-tile            SiriusPreferenceHeader:clickTag="@string/app_my"            SiriusPreferenceHeader:icon="@drawable/icon_service"            SiriusPreferenceHeader:isSelectedTab="true"            SiriusPreferenceHeader:selectIcon="@drawable/icon_extension"            SiriusPreferenceHeader:title="@string/app_my">            <intent                android:action="android.intent.action.MAIN"                android:targetClass="com.mediatek.systemupdate.MainEntry"                android:targetPackage="com.mediatek.systemupdate" />        </dashboard-tile>    </dashboard-category></dashboard-categories>


这个XML文件用到我们自定义的属性

 <declare-styleable name="SiriusPreferenceHeader">        <!--底部tab标题-->        <attr name="title" format="string" />        <attr name="summary" format="string" />        <!--底部tab icon图片-->        <attr name="icon" format="reference" />        <attr name="fragment" format="string" />        <!--底部tab 点击事件的Tag标签-->        <attr name="clickTag" format="string" />        <!--是否是当前tab标志位-->        <attr name="isSelectedTab" format="boolean" />        <!--如果是当前tab 选中icon-->        <attr name="selectIcon" format="reference" />    </declare-styleable>


到这一步我们要将每个Tab的点击Intent,选中未选中的状态Icon,还有title都已经定义出来

下一步就是要将我们去解析XML生成对象然后实现自定义View

我们直接上代码看一下怎么去解析这种XML,并且自定义类似于ListView的LinearLayout


package com.ucon.libraryview.tabselectview;import android.content.Context;import android.content.Intent;import android.content.res.TypedArray;import android.content.res.XmlResourceParser;import android.database.DataSetObserver;import android.os.Bundle;import android.text.TextUtils;import android.util.AttributeSet;import android.util.Log;import android.util.TypedValue;import android.util.Xml;import android.view.Gravity;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.LinearLayout;import com.ucon.libraryview.R;import com.ucon.libraryview.model.TabInfo;import com.ucon.libraryview.util.XmlUtils;import org.xmlpull.v1.XmlPullParser;import org.xmlpull.v1.XmlPullParserException;import java.io.IOException;import java.util.ArrayList;import java.util.List;/** * Created by Zhongqi.Shao on 2017/6/2. */public class TabView extends LinearLayout implements View.OnClickListener {    private List<View> mViewList = new ArrayList<View>();    private List<TabInfo> mTargetInfoList;    private int mBgColor;    private BaseAdapter mAdapter;    public TabView(Context context) {        super(context);        setOrientation(HORIZONTAL);    }    public TabView(Context context, AttributeSet attrs) {        super(context, attrs);        setOrientation(HORIZONTAL);        TypedArray typeArray = context.obtainStyledAttributes(attrs, R.styleable.TabSelectView);        mBgColor = typeArray.getColor(R.styleable.TabSelectView_tab_back, 0);        this.setBackgroundColor(mBgColor);        typeArray.recycle();    }    public void setAdapter(BaseAdapter baseAdapter) {        mViewList.clear();        this.removeAllViews();        if (mAdapter != null) {            mAdapter.unregisterDataSetObserver(mObserVable);        }        mAdapter = baseAdapter;        mAdapter.registerDataSetObserver(mObserVable);        bindListView();    }    private void bindListView() {        if (mAdapter == null) {            return;        }        int count = mAdapter.getCount();        for (int i = 0; i < count; i++) {            View itemView = mAdapter.getView(i, null, null);            itemView.setOnClickListener(this);            LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f);            layoutParams.gravity = Gravity.CENTER;            itemView.setLayoutParams(layoutParams);            this.addView(itemView);        }    }    @Override    public void onClick(View itemView) {        String clickTag = (String) itemView.getTag();        if (mTargetInfoList != null && mTargetInfoList.size() > 0 && !TextUtils.isEmpty(clickTag)) {            for (TabInfo tag : mTargetInfoList) {                if (tag.clickTag.equals(clickTag)) {                    getContext().startActivity(tag.intent);                }            }        }    }    private DataSetObserver mObserVable = new DataSetObserver() {        @Override        public void onChanged() {            super.onChanged();            mViewList.clear();            bindListView();        }        @Override        public void onInvalidated() {            super.onInvalidated();            mViewList.clear();            bindListView();        }    };    public void loadCategoriesFromResource(int resid, List<TabInfo> target) {        mTargetInfoList = target;        XmlResourceParser parser = null;        try {            parser = getResources().getXml(resid);            AttributeSet attrs = Xml.asAttributeSet(parser);            int type;            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT                    && type != XmlPullParser.START_TAG) {            }            String nodeName = parser.getName();            if (!"dashboard-categories".equals(nodeName)) {                throw new RuntimeException(                        "XML document must start with <preference-categories> tag; found"                                + nodeName + " at " + parser.getPositionDescription());            }            Bundle curBundle = null;            final int outerDepth = parser.getDepth();            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {                    continue;                }                nodeName = parser.getName();                if ("dashboard-category".equals(nodeName)) {                    TypedArray sa = getContext().obtainStyledAttributes(                            attrs, R.styleable.SiriusPreferenceHeader);                    TypedValue tv = sa.peekValue(R.styleable.SiriusPreferenceHeader_title);                    if (tv != null && tv.type == TypedValue.TYPE_STRING) {                    }                    sa.recycle();                    final int innerDepth = parser.getDepth();                    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT                            && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {                        if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {                            continue;                        }                        String innerNodeName = parser.getName();                        if (innerNodeName.equals("dashboard-tile")) {                            TabInfo tile = new TabInfo();                            Log.d("shao", "in tag");                            sa = getContext().obtainStyledAttributes(                                    attrs, R.styleable.SiriusPreferenceHeader);                            tv = sa.peekValue(R.styleable.SiriusPreferenceHeader_title);                            if (tv != null && tv.type == TypedValue.TYPE_STRING) {                                tile.title = tv.string;                            }                            tv = sa.peekValue(R.styleable.SiriusPreferenceHeader_clickTag);                            if (tv != null && tv.type == TypedValue.TYPE_STRING) {                                tile.clickTag = tv.string;                            }                            tile.isSelectedTab = sa.getBoolean(R.styleable.SiriusPreferenceHeader_isSelectedTab, false);                            tile.iconRes = sa.getDrawable(R.styleable.SiriusPreferenceHeader_icon);                            tile.iconSelectedRes = sa.getDrawable(R.styleable.SiriusPreferenceHeader_selectIcon);                            tile.fragment = sa.getString(R.styleable.SiriusPreferenceHeader_fragment);                            sa.recycle();                            if (curBundle == null) {                                curBundle = new Bundle();                            }                            final int innerDepth2 = parser.getDepth();                            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT                                    && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth2)) {                                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {                                    continue;                                }                                String innerNodeName2 = parser.getName();                                if (innerNodeName2.equals("extra")) {                                    getResources().parseBundleExtra("extra", attrs, curBundle);                                    XmlUtils.skipCurrentTag(parser);                                } else if (innerNodeName2.equals("intent")) {                                    tile.intent = Intent.parseIntent(getResources(), parser, attrs);                                } else {                                    XmlUtils.skipCurrentTag(parser);                                }                            }                            if (curBundle.size() > 0) {                                tile.fragmentArguments = curBundle;                                curBundle = null;                            }                            target.add(tile);                        } else {                            XmlUtils.skipCurrentTag(parser);                        }                    }                } else {                    XmlUtils.skipCurrentTag(parser);                }            }        } catch (XmlPullParserException e) {            throw new RuntimeException("Error parsing categories", e);        } catch (IOException e) {            throw new RuntimeException("Error parsing categories", e);        } finally {            if (parser != null) parser.close();        }    }}


解析XML封装成Item对象的代码:

package com.ucon.libraryview.model;import android.content.Intent;import android.graphics.drawable.Drawable;import android.os.Bundle;import java.io.Serializable;/** * Created by Zhongqi.Shao on 2017/6/2. */public class TabInfo implements Serializable {    public int titleRes;    /**     * Title of the tile that is shown to the user.     *     * @attr ref android.R.styleable#PreferenceHeader_title     */    public CharSequence title;    public CharSequence clickTag;    /**     * Resource ID of optional summary describing what this tile controls.     *     * @attr ref android.R.styleable#PreferenceHeader_summary     */    public int summaryRes;    /**     * Optional summary describing what this tile controls.     *     * @attr ref android.R.styleable#PreferenceHeader_summary     */    public CharSequence summary;    /**     * Optional icon resource to show for this tile.     *     * @attr ref android.R.styleable#PreferenceHeader_icon     */    public Drawable iconRes;    public Drawable iconSelectedRes;    public boolean isSelectedTab;    /**     * Full class name of the fragment to display when this tile is     * selected.     *     * @attr ref android.R.styleable#PreferenceHeader_fragment     */    public String fragment;    /**     * Optional arguments to supply to the fragment when it is     * instantiated.     */    public Bundle fragmentArguments;    /**     * Intent to launch when the preference is selected.     */    public Intent intent;    /**     * Optional additional data for use by subclasses of the activity     */    public Bundle extras;    public TabInfo() {        // Empty    }}


到这一步功能的主线已经出来了

完整代码可以从gitHub上面下载 https://github.com/ShaoZhongqi2359/SelectedTab.git



阅读全文
1 0
原创粉丝点击