自定义View之TitleBar

来源:互联网 发布:意大利火车时刻表软件 编辑:程序博客网 时间:2024/06/08 05:03

自定义Titlebar –进阶

在之前的自定义View中也曾写过自定义标题栏,但当时只是为了学习而写了一个简单的例子,功能比较简单,只是作为一个练习使用。这次搞了一个自定义能力比较强的TitleBar,满足了日常的需求。

一般的app标题栏一般分为左,中,右三部分,左部分基本上都是返回按钮,特殊情况下为自定义菜单,而中,右侧菜单只是完成了基本功能。

原理很简单,只是把一些布局进行封装成一个控件,并添加一些逻辑,难度上不是很大。

先上图
这里写图片描述

  • 根据我们的规划,在xml中因该有如下基本的属性
    • 左侧分为三个模式:返回,自定义菜单,不显示。
    • 中部分为两个模式:自定义菜单,不显示。
    • 右侧分为两个模式:自定义菜单,不显示。

定义attrs属性:

<declare-styleable name="TitleBar">        <attr name="leftType" >            <enum name="gone" value="0"/>            <enum name="customMenu" value="1"/>            <enum name="back" value="2"/>        </attr>        <attr name="leftText" format="string" />        <attr name = "leftImage" format="reference"/>        <attr name="centerType">            <enum name="gone" value="0"/>            <enum name ="customMenu" value="1"/>        </attr>        <attr name="centerText" format="string"/>        <attr name="rightType">            <enum name="gone" value="0"/>            <enum name="customMenu" value="1"/>        </attr>        <attr name="rightText" format="string"/>    </declare-styleable>

在定义Type属性的时候,使用到了枚举类型,该属性类似于我们常用的grivaty属性一样给你固定的几个选项,在这里需要注意的是枚举类型获取其值时获取到的是其对应的value中的整型值。

  • 布局widget_titlebar.xml文件。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="48dp"    android:layout_marginBottom="5dp"    android:background="#fff"    android:elevation="5dp"    android:orientation="vertical">    <LinearLayout        android:id="@+id/ll_titlebar_left"        android:layout_width="wrap_content"        android:layout_height="match_parent"        android:layout_marginLeft="5dp"        android:gravity="center">        <ImageView            android:id="@+id/iv_titlebar_left"            android:layout_width="40dp"            android:layout_height="40dp"            android:layout_gravity="center"            android:src="@mipmap/back_1" />        <TextView            android:id="@+id/tv_titlebar_left"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_gravity="center"            android:text="左侧标题"            android:textSize="18sp" />    </LinearLayout>    <LinearLayout        android:id="@+id/ll_titlebar_center"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_centerInParent="true"        android:gravity="center">        <TextView            android:id="@+id/tv_titlebar_center"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="中标题"            android:textColor="#222"            android:textSize="20sp" />    </LinearLayout>    <LinearLayout        android:id="@+id/ll_titlebar_right"        android:layout_width="wrap_content"        android:layout_height="match_parent"        android:layout_alignParentRight="true"        android:layout_marginRight="10dp"        android:gravity="center">        <TextView            android:id="@+id/tv_titlebar_right"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_gravity="center"            android:text="右侧按钮"            android:textSize="18sp" />    </LinearLayout></RelativeLayout>

布局上没有什么问题,唯一需要注意是elevation属性,在这里定义了阴影偏移为5dp,一开始,我定义的时候,在我们的布局显示上可以看到阴影,但在真机和模拟器调试上确无法看到,这里有几个很重要的点。
1. 需要定义该布局的背景颜色。
2. 需要添加一个margin属性。应该我们定义了偏移量之后,在父控件中并没有考虑到该控件的偏移量大小,导致给该控件留的大小刚好等于控件自身大小,导致偏移量无法显示。

  • 在Java中获取属性,并查找控件
    /**     * 获取自定义属性     *     * @param context     * @param attrs     */    private void initAttrs(Context context, AttributeSet attrs) {        if (attrs != null) {            TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TitleBar);            mLeftText = ta.getString(R.styleable.TitleBar_leftText);            mLeftType = ta.getInteger(R.styleable.TitleBar_leftType, TYPE_BACK);            mLeftImage = ta.getDrawable(R.styleable.TitleBar_leftImage);            mCenterType = ta.getInteger(R.styleable.TitleBar_centerType, TYPE_CUSTOM_MENU);            mCenterText = ta.getString(R.styleable.TitleBar_centerText);            mRightType = ta.getInteger(R.styleable.TitleBar_rightType, TYPE_GONE);            mRightText = ta.getString(R.styleable.TitleBar_rightText);        }    }   /**     * 查找控件id     */    private void initView() {        mLeftLinearLayout = (LinearLayout) findViewById(R.id.ll_titlebar_left);        mLeftImageView = (ImageView) findViewById(R.id.iv_titlebar_left);        mLeftTextView = (TextView) findViewById(R.id.tv_titlebar_left);        mCenterTextView = (TextView) findViewById(R.id.tv_titlebar_center);        mCenterLinearLayout = (LinearLayout) findViewById(R.id.ll_titlebar_center);        mRightTextView = (TextView) findViewById(R.id.tv_titlebar_right);        mRightLinearLayout = (LinearLayout) findViewById(R.id.ll_titlebar_right);    }
  • 根据xml文件属性初始化状态,
    /**     * 加载默认视图     */    private void loadView() {        if (mLeftType == TYPE_BACK) {            mLeftText = "返回";            mLeftTextView.setVisibility(View.VISIBLE);            mLeftTextView.setText(mLeftText);            mLeftImageView.setImageResource(R.mipmap.back_1);            mLeftImageView.setVisibility(View.VISIBLE);        } else if (mLeftType == TYPE_CUSTOM_MENU) {            if (mLeftImage == null) {                mLeftImageView.setVisibility(View.GONE);            } else {                mLeftImageView.setVisibility(View.VISIBLE);                mLeftImageView.setImageDrawable(mLeftImage);            }            if (!TextUtils.isEmpty(mLeftText)) {                mLeftTextView.setVisibility(View.VISIBLE);                mLeftTextView.setText(mLeftText);            } else {                mLeftTextView.setVisibility(View.GONE);            }        } else if (mLeftType == TYPE_GONE) {            mLeftTextView.setVisibility(View.GONE);            mLeftImageView.setVisibility(View.GONE);        }        if (mCenterType == TYPE_CUSTOM_MENU) {            if (!TextUtils.isEmpty(mCenterText)) {                mCenterTextView.setVisibility(View.VISIBLE);                mCenterTextView.setText(mCenterText);            } else {                mCenterTextView.setVisibility(View.GONE);            }        } else if (mCenterType == TYPE_GONE) {            mCenterTextView.setVisibility(View.GONE);        }        if (mRightType == TYPE_CUSTOM_MENU) {            if (!TextUtils.isEmpty(mRightText)) {                mRightTextView.setVisibility(View.VISIBLE);                mRightTextView.setText(mRightText);            } else {                mRightTextView.setVisibility(View.GONE);            }        } else if (mRightType == TYPE_GONE) {            mRightTextView.setVisibility(View.GONE);        }    }
  • 设置监听回调。定义监听回调类,在这里为了省事定义成了内部类
    /**     * 监听回调事件     */    public static abstract class TitleBarClickListener {        public abstract void onLeftClick();        public void onCenterClick() {        }        public void onRightClick() {        }    }

因为对于标题栏,使用最多的是左侧按钮,所以在这里定义个抽象类,必须实现左侧点击,中心和右侧选择定义。因为使用了抽象类,相比于接口来说,继承不是很方便,有利有弊吧。

  • 创建监听方法,并实现回调
   /**     * @param mTitleBarClickListener     */    public void setTitleBarClickListener(TitleBarClickListener mTitleBarClickListener) {        this.mTitleBarClickListener = mTitleBarClickListener;    }    /**     * 设置左右菜单的监听     */    private void initClick() {        mLeftLinearLayout.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                if (mTitleBarClickListener != null) {                    mTitleBarClickListener.onLeftClick();                }            }        });        mCenterLinearLayout.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                if (mTitleBarClickListener != null) {                    mTitleBarClickListener.onCenterClick();                }            }        });        mRightLinearLayout.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                if (mTitleBarClickListener != null) {                    mTitleBarClickListener.onRightClick();                }            }        });    }
  • 最后对于左中右菜单可能会有一些比较特别的布局,添加如下方法
 public void addLeftView(View view) {        mLeftLinearLayout.removeAllViews();        mLeftLinearLayout.addView(view);    }    public void addCenterView(View view) {        mCenterLinearLayout.removeAllViews();        mCenterLinearLayout.addView(view);    }    public void addRightView(View view) {        mRightLinearLayout.removeAllViews();        mRightLinearLayout.addView(view);    }
  • 最后一步,添加布局文件。
<mahao.alex.titlebar.TitleBar        android:id="@+id/titlebar1"        app:leftType="back"        app:centerType="gone"        app:rightType="gone"        android:layout_width="match_parent"        android:layout_height="wrap_content"/>    <mahao.alex.titlebar.TitleBar        android:id="@+id/titlebar2"        android:layout_marginTop="40dp"        app:leftType="customMenu"        app:leftImage="@mipmap/ic_launcher"        app:leftText="自定义"        app:centerType="customMenu"        app:centerText="自定义中"        app:rightType="customMenu"        app:rightText="右菜单"        android:layout_width="match_parent"        android:layout_height="wrap_content"/>
public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        requestWindowFeature(Window.FEATURE_NO_TITLE);        setContentView(R.layout.activity_main);        ((TitleBar) findViewById(R.id.titlebar1)).setTitleBarClickListener(new TitleBar.TitleBarClickListener(){            @Override            public void onLeftClick() {                Toast.makeText(MainActivity.this, "back", Toast.LENGTH_SHORT).show();            }        });        ((TitleBar) findViewById(R.id.titlebar2)).setTitleBarClickListener(new TitleBar.TitleBarClickListener(){            @Override            public void onLeftClick() {                Toast.makeText(MainActivity.this, "左菜单", Toast.LENGTH_SHORT).show();            }            @Override            public void onCenterClick() {                Toast.makeText(MainActivity.this, "中", Toast.LENGTH_SHORT).show();            }            @Override            public void onRightClick() {                Toast.makeText(MainActivity.this, "右", Toast.LENGTH_SHORT).show();            }        });    }}

现在只是V1.0版本,后续继续改进o(^▽^)o。

待改进
- 点击效果
- 菜单大小,颜色。。。

该代码已上传至github..有兴趣者请移步https://github.com/AlexSmille/TitleBar

0 0
原创粉丝点击