自定义View之TitleBar

自定义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

你可能感兴趣的:(标题栏,自定义view,titlebar)