打造自己想要风格的 ActionBar

很久没更新 blog 了,最近在赶一个项目,所以时间特别紧,自己闲暇的时间也就少了许多,最近我的好朋友们一直在群里喊,杀!杀!杀!也都抽不出时间陪他们玩!今天周末,终于可以放松一下了,先更新 blog!^V^~~~~。

我们知道 Android ActionBar 的功能很强大,经过 Google 的改良后,使用起来页很灵活和便捷,但是!再好的东西都有它所不能及的一面,就像在豪华的别墅都应该有一个小小的 WC,就像…都有…,这里就不往下了。回到 ActionBar,有哪些它无法做到呢?
我们还是来看一张效果图

这里写图片描述

这种效果的 ActionBar,在 ActionBar 上添加一个按钮的效果,如果要用 原生的ActionBar实现够呛!虽然说可以通过 setView 来实现但是,个人感觉比较麻烦!ok,如果不用 setView 的方式来实现,那我们就只能通过自定义 布局 来实现,而把原来的 ActionBar 给隐藏掉。代码我相信大家都会写
如下:分三步走
第一步:编写 custom bar layout

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"                android:layout_width="match_parent"                android:layout_height="@dimen/abc_action_bar_default_height_material"  android:background="#ffffff">

    <View
        android:layout_width="match_parent"
        android:layout_height="0.5dp"
        android:background="#eeeeee"
        android:layout_alignParentBottom="true"/>
    <RelativeLayout
        android:id="@+id/id_actionBar_back"        android:layout_width="@dimen/abc_action_bar_default_height_material"        android:layout_height="@dimen/abc_action_bar_default_height_material"
        android:clickable="true"
        android:background="@drawable/actionbar_back_bg"
        android:layout_marginBottom="0.5dp"
        >

        <ImageView
            android:id="@+id/id_actionBar_back_icon"
            android:layout_centerInParent="true"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/ic_ab_back_black"
            />
    </RelativeLayout>


    <TextView
        android:layout_toRightOf="@id/id_actionBar_back"
        android:id="@+id/id_actionBar_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_toLeftOf="@+id/id_actionBar_confirm"
        android:text="自己定义"
        android:singleLine="true"
        android:textSize="20sp"
        android:textColor="#333333"
        />

    <Button

        android:layout_width="52dp"
        android:layout_height="32dp"
        android:id="@+id/id_actionBar_confirm"
        android:text="保 存"
        android:background="@drawable/color_btn_selector"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:textSize="14sp"
        android:textColor="@android:color/white"
        android:gravity="center"
        android:layout_marginRight="10dp"
        />
</RelativeLayout>

第二步:在用使用的布局文件中嵌入这个布局

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    >

    <include layout="@layout/custom_actionbar_layout"
        android:id="@+id/id_custom_actionBar"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="22sp"
        android:layout_centerInParent="true"
        android:textColor="@color/btn_color_normal"
        android:text="自己的ActionBar"/>

</RelativeLayout>

最后一步:
在代码中设置点击事件等等操作

    private void initCustomBar(){
        mCustomBar = findViewById(R.id.id_custom_actionBar) ;
        mBackBtn = mCustomBar.findViewById(R.id.id_actionBar_back) ;
        mTitle = (TextView) mCustomBar.findViewById(R.id.id_actionBar_title);
        mConfirmBtn = (Button) mCustomBar.findViewById(R.id.id_actionBar_confirm) ;
        mIcon = (ImageView) mCustomBar.findViewById(R.id.id_actionBar_back_icon) ;
        mBackBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
        mTitle.setText(getTitle());
        mConfirmBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this,MyBarActivity.class) ;
                startActivity(intent);
                Toast.makeText(MainActivity.this,"点击了保存按钮",Toast.LENGTH_SHORT).show();
            }
        });
    }

运行结果如下

这里写图片描述

嘿!效果不错,大功告成,可以提交代码了,可是过了一段时间,设计把其他页面的设计结果给你一看,哇,类似这种在 AcionBar 上加一个按钮的界面还有七八个,没办法了,只能复制、粘贴,复制、粘贴,复制、粘贴。可是作为一位合格的码农,应该清楚,只要是能重复利用的东西,我们都是能够抽取出来的,而我们也应该要把它抽取出来!接下来就进入本篇 blog 的核心内容。
我们的大致思路是这样的:
定义一个抽象的父类 Activity,在这个类中实现我们自己风格的 ActionBar,而其他类只需要继承这个类就能实现这样的 ActionBar 风格,并在子类中能设置监听按钮事件,修改标题内容等等一系列操作!

要实现这样一个抽象类,其实仔细想想也不难,这里我就直接上代码了:

package com.test.gyzhong.customactionbar;

import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;


/**
 * Created by gyzhong on 15/4/17.
 */
public abstract class CustomBarActivity extends ActionBarActivity {

    /*我们定义的ActionBar*/
    private View mCustomBar ;
    /*放回按钮*/
    private View mBackBtn ;
    /*确定按钮*/
    private Button mConfirmBtn ;
    /*标题View*/
    private TextView mTitle ;
    /*返回箭头*/
    private ImageView mIcon ;
    /*返回按钮菜单*/
    private MenuItemImpl mBackMenuItem ;
    /*标题菜单*/
    private MenuItemImpl mBackMenuTitle;
    /*确定按钮菜单*/
    private MenuItemImpl mConfirmMenuItem ;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /*隐藏系统的ActionBar*/
        getSupportActionBar().hide();
        /*初始化自己定义的ActionBar*/
        initCustomBar() ;
    }

    private void initCustomBar(){
        /*不解释*/
        mCustomBar = getLayoutInflater().inflate(R.layout.custom_actionbar_layout, null) ;
        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                (int) getResources().getDimension(R.dimen.abc_action_bar_default_height_material));
        mBackBtn = mCustomBar.findViewById(R.id.id_actionBar_back) ;
        mCustomBar.setLayoutParams(params);
        mTitle = (TextView) mCustomBar.findViewById(R.id.id_actionBar_title);
        mConfirmBtn = (Button) mCustomBar.findViewById(R.id.id_actionBar_confirm) ;
        mIcon = (ImageView) mCustomBar.findViewById(R.id.id_actionBar_back_icon) ;
        mBackBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onOptionsItemSelected(mBackMenuItem) ;
            }
        });
        mTitle.setText(getTitle());
        mConfirmBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onOptionsItemSelected(mConfirmMenuItem) ;
            }
        });
    }

    @Override
    public void setContentView(int layoutResID) {
        super.setContentView(layoutResID);
        /*创建一个线性布局*/
        LinearLayout content = new LinearLayout(this) ;
        ViewGroup.LayoutParams contentParam = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT) ;
        /*
        *设置线性布局的方向为垂直
        * 第一个子View 为我们定义的ActionBar
        * 第二个子View 是我们整个 activity 原来的布局
        * 
        * */
        content.setOrientation(LinearLayout.VERTICAL);
        content.setLayoutParams(contentParam);
        content.addView(mCustomBar);

        /*
        * 
        * 以下操作的意思是:
        * 从原来父View 中把原来Activity 的内容View 移除掉,
        * 放入我们自己创建的那个线性布局,
        * 因为线性布局中包含自己定义的ActionBar
        * 和原来的内容区域,所以,最总就是我们想要的效果
        * */
        ViewGroup baseGroup = (ViewGroup) findViewById(android.R.id.content);
        View originView = baseGroup.getChildAt(0) ;
        baseGroup.removeView(originView);
        content.addView(originView);
        baseGroup.addView(content);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()){
            case R.id.id_actionBar_back:{
                finish();
                return true ;
            }
        }
        return super.onOptionsItemSelected(item);
    }

    /*----------------------------以下操作是为了迎合我们的习惯----------------------*/
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        MenuItem menuItem = menu.findItem(R.id.id_actionBar_confirm);
        if (menuItem != null){
            setActionBarCompatConfirmText(menuItem.getTitle());
        }
        menuItem = menu.findItem(R.id.id_actionBar_title);
        if (menuItem != null){
            setActionBarCompatTitle(menuItem.getTitle());
        }
        mBackMenuItem = new MenuItemImpl() ;
        mBackMenuItem.addMenuItem(mBackBtn,R.id.id_actionBar_back);
        mBackMenuTitle = new MenuItemImpl() ;
        mBackMenuTitle.addMenuItem(mTitle,R.id.id_actionBar_title);
        mConfirmMenuItem = new MenuItemImpl() ;
        mConfirmMenuItem.addMenuItem(mConfirmBtn,R.id.id_actionBar_confirm);
        return super.onCreateOptionsMenu(menu);
    }


    /*=========================以下方法是自定义Bar 的一些控制方法=======================*/
    public View getActionBarCompat(){
        return mCustomBar ;
    }

    public TextView getActionBarCompatTextView(){
        return mTitle ;
    }

    public Button getActionBarCompatConfirmBtn(){
        return mConfirmBtn ;
    }

    public void setActionBarCompatBg(int color){
        mCustomBar.setBackgroundColor(color);
    }

    public void setActionBarCompatBg(Drawable bg){
        mCustomBar.setBackgroundDrawable(bg);
    }

    public void setActionBarCompatHide(){
        mCustomBar.setVisibility(View.GONE);
    }

    public void setActionBarCompatTitle(CharSequence title){
        mTitle.setText(title);
    }

    public void setActionBarCompatTitle(int title){
        mTitle.setText(title);
    }

    public void setActionBarCompatTitleColor(int color){
        mTitle.setTextColor(color);
    }

    public void setActionBarCompatTitleColor(ColorStateList color){
        mTitle.setTextColor(color);
    }

    public void setActionBarCompatConfirmText(CharSequence title){
        mConfirmBtn.setText(title);
    }

    public void setActionBarCompatConfirmText(int title){
        mConfirmBtn.setText(title);
    }

    public void setActionBarCompatIcon(int iconRes) {
        mIcon.setImageResource(iconRes);
    }

    public void setActionBarCompatIcon(Drawable icon) {
        mIcon.setImageDrawable(icon);
    }
}

接下来看看如何使用它吧,看完之后会让你惊艳的!

1、使用的 Activity 代码

/**
 * Created by gyzhong on 15/4/17.
 */
public class MyBarActivity extends CustomBarActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_bar_view);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if(item.getItemId() == R.id.id_actionBar_confirm){
            Toast.makeText(this,item.getTitle() + "按钮被点击了",Toast.LENGTH_SHORT).show();
        }
        return super.onOptionsItemSelected(item);
    }
}

2、xml 代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:textSize="22sp"
        android:gravity="center"
        android:textColor="@color/btn_color_normal"
        android:text="自己的ActionBar"/>
</LinearLayout>

我们的 Activity 和布局文件中什么都不需要做,唯一要实现的就是继承我们定义的抽象类,所以不管以后你有几十个这样的页面甚至几百个,我们都不需要做任何处理。

运行结果:

这里写图片描述

总结

这篇文章的技术难点,可以说没什么技术难点,最主要的还是在开发的过程中,不断的总结,优化我们的代码。我在看别人的代码的时候,经常会带着欣赏的眼光去看,有时一份好的代码,会让我回味无穷。

点击下载

源码

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值