自定义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
- 自定义View之TitleBar
- 自定义View之TitleBar
- 简单自定义View之TitleBar
- Android自定义View之TitleBar,通用标题栏
- [Android]自定义View标题栏TitleBar
- Android自定义view,titlebar的返回按钮
- 自定义 TitleBar
- 自定义TitleBar
- 自定义titlebar
- 自定义TitleBar
- 自定义TitleBar
- Android开发之自定义ActionBar和TitleBar
- Android开发随笔之自定义TitleBar
- android中自定义控件之TitleBar实现
- Android自定义View-TitleBar(标题栏)详细说明
- androidUI开发之自定义Android标题栏TitleBar布局
- Android开发之——自定义标题栏titlebar
- 自定义Android标题栏TitleBar
- 【bzoj3564】 [SHOI2014]信号增幅仪
- 第八道ACM程序题
- iOS Crash收集框架
- C# 使用Linq
- 【模态窗】制作适合手机页面的模态弹窗
- 自定义View之TitleBar
- C# Linq复杂一点的查询
- Android MediaPlayer状态机 接口 方法解析
- selector
- FBO离屏渲染技术
- c++ 链表类创建 demo
- 获取radio点击事件
- js 判断点是否在多边形内
- Lua_第 20 章 IO库