Android进阶——自定义View之重写ViewGroup组合系统控件实现自定义ToolBar模板

本文介绍了一种基于Android系统的自定义ToolBar实现方法,通过继承RelativeLayout并结合LayoutInflater来快速构建一个可定制化的顶部导航栏,支持动态修改背景、图标及监听点击事件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引言

前一篇文章Android进阶——自定义View之继承系统控件实现自带删除按钮和设置动画效果的加强型EditText通过去继承EditText实现一个自带删除和抖动动画效果的EditText,这篇同样是继承系统控件,不过是去扩展ViewGroup,相信做过Web或者WinForm的同学都对模板不陌生,虽然Android中并没有这个概念,不过思想我们是可以借鉴的,这也是通过组合系统控件实现自定义View的一大优势,其实就是像一个模板,我们可以应用在我们的APP中,统一去管理他的样式和风格,维护成本也很低。

一、自定义ToolBar概述

虽然Android已经为我们提供了ActionBar和ToolBar,但是有些时候需要客制化的时候还是不能满足具体的业务需求,于是乎我就采用了重写ViewGroup组合系统控件去实现,类似ActionBar和ToolBar的一个小控件。
这里写图片描述

二、自定义ToolBar的设计思想

1、选择继承RelativeLayout

选择继承RelativeLayout,其实RelativeLayout的布局机制也是有点类似FrameLayout,选择继承RelativeLayout可以在我们的使用的时候更方便简单,不需要再重新布局。

2、实现ToolBar的UI效果

一般来说继承系统控件,大多都是在它的构造方法里做文章,至于添加其他View,也有很多种方式可以通过LayoutInflater.from(context).inflate(layoutid, this, true)映射布局xml或者通过Java代码动态构造再addView添加进去。

private void init(AttributeSet attrs) {

        View contentView = LayoutInflater.from(this.context).inflate(R.layout.navtop_layout, this, true);
        imageLeft = (ImageView) contentView.findViewById(R.id.id_nav_left);
        imageRight = (ImageView) contentView.findViewById(R.id.id_nav_right);
        topBg = (RelativeLayout) contentView.findViewById(R.id.rl_top_bg);
        textView = (TextView) contentView.findViewById(R.id.id_mid_nav);
        initAttr(attrs);
        topBg.setBackgroundColor(bcgroundResId);
        imageLeft.setOnClickListener(this);
        imageRight.setOnClickListener(this);
    }

3、把控件的属性成员开放出来用于客制化

   /**
     * 设置默认的左边按钮的背景图
     * @param resouseId
     */
    public void setLeftImage(int resouseId) {
        imageLeft.setImageResource(resouseId);
    }

    public void setRightImage(int resouseId) {
        imageRight.setImageResource(resouseId);
    }

    /**
     * 设置是否显示左右按钮
     * @param left
     * @param right
     */
    public void setBarImageDisplay(boolean left, boolean right) {
        if(left){
            imageLeft.setVisibility(VISIBLE);
        }else {
            imageLeft.setVisibility(GONE);
        }
        if(right) {
            imageRight.setVisibility(VISIBLE);
        }else {
            imageRight.setVisibility(GONE);
        }
    }

4、添加人机交互接口

参考ToolBar这个小控件主要操作其实就只需要有:动态显示或隐藏指定View,动态改变显示Title和点击动作。

 public void setNavOnClickListener(NavOnClickListener onClickListener) {
        navOnClickListener = onClickListener;
    }

    public interface NavOnClickListener {
        void leftOnClickListener();
        void rightOnClickListener();
    }

三、实现自定义ToolBar

package com.crazymo.views.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.crazymo.views.R;

/**
 * auther: Crazy.Mo
 * Date: 2016/12/26
 * Time:18:08
 * Des:
 */
public class NavTopBar extends RelativeLayout implements View.OnClickListener {
    private Context context;
    private TextView textView;
    private ImageView imageRight;
    private ImageView imageLeft;
    private NavOnClickListener navOnClickListener;
    private RelativeLayout topBg;
    private int bcgroundResId;
    private Drawable leftImgId,rightImgId;

    public NavTopBar(Context context) {
        super(context);
        this.context = context;
    }

    public NavTopBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        init(attrs);
    }

    public NavTopBar(@NonNull Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        init(attrs);
    }

    private void init(AttributeSet attrs) {

        View contentView = LayoutInflater.from(this.context).inflate(R.layout.navtop_layout, this, true);
        imageLeft = (ImageView) contentView.findViewById(R.id.id_nav_left);
        imageRight = (ImageView) contentView.findViewById(R.id.id_nav_right);
        topBg = (RelativeLayout) contentView.findViewById(R.id.rl_top_bg);
        textView = (TextView) contentView.findViewById(R.id.id_mid_nav);
        initAttr(attrs);
        //topBg.setBackgroundResource(bcgroundResId);
        topBg.setBackgroundColor(bcgroundResId);
        imageLeft.setOnClickListener(this);
        imageRight.setOnClickListener(this);
    }

    private void initAttr(AttributeSet attrs){
        TypedArray types = context.obtainStyledAttributes(attrs,
                R.styleable.nav_top_bar);
        try {
            bcgroundResId = types.getColor( R.styleable.nav_top_bar_bacgroud_color,getResources().getColor(R.color.blue ));
        } finally {
            types.recycle(); // TypeArray用完需要recycle
        }
    }

    @Override
    public void onClick(View v) {
        if (navOnClickListener != null) {
            switch (v.getId()) {
                case R.id.id_nav_left:
                    navOnClickListener.leftOnClickListener();
                    break;
                case R.id.id_nav_right:
                    navOnClickListener.rightOnClickListener();
                    break;
            }
        }
    }

    public void setNavBackground(int resId){
        topBg.setBackgroundResource(resId);
    }

    public void setTitle(String title) {
        textView.setText(title);
    }

    public void setNavOnClickListener(NavOnClickListener onClickListener) {
        navOnClickListener = onClickListener;
    }

    public interface NavOnClickListener {
        void leftOnClickListener();
        void rightOnClickListener();
    }

    /**
     * 设置默认的左边按钮的背景图
     * @param resouseId
     */
    public void setLeftImage(int resouseId) {
        imageLeft.setImageResource(resouseId);
    }

    public void setRightImage(int resouseId) {
        imageRight.setImageResource(resouseId);
    }

    /**
     * 设置是否显示左右按钮
     * @param left
     * @param right
     */
    public void setBarImageDisplay(boolean left, boolean right) {
        if(left){
            imageLeft.setVisibility(VISIBLE);
        }else {
            imageLeft.setVisibility(GONE);
        }
        if(right) {
            imageRight.setVisibility(VISIBLE);
        }else {
            imageRight.setVisibility(GONE);
        }
    }
}

四、使用自定义ToolBar

属性attr.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="nav_top_bar">
        <attr name="bacgroud_color" format="reference"/>
    </declare-styleable>
</resources>

布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:crazymo="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.crazymo.views.MainActivity">

    <com.crazymo.views.widget.NavTopBar
        android:id="@+id/nav_top_main"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        crazymo:bacgroud_color="@color/colorPrimary"
    />
    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@mipmap/ic_crazymo_logo"/>

</RelativeLayout>

MainActivity

package com.crazymo.views;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ImageView;
import android.widget.Toast;

import com.crazymo.views.widget.NavTopBar;

/**
 * auther: Crazy.Mo
 * Date: 2016/12/26
 * Time:18:20
 * Des:
 */
public class MainActivity extends AppCompatActivity implements NavTopBar.NavOnClickListener{
    private NavTopBar navTopBar;
    private ImageView leftBtn,rightBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initViews();
    }

    private void initViews(){
        navTopBar= (NavTopBar) findViewById(R.id.nav_top_main);
        navTopBar.setBarImageDisplay(true,true);//设置显示左右按钮
        navTopBar.setNavOnClickListener(this);//注册监听
        setTitle("ByCrazyMo_");
    }

    private void setTitle(String title){
        navTopBar.setTitle(title);
    }

    @Override
    public void leftOnClickListener() {
        Toast.makeText(this,"Clicked on the Left",Toast.LENGTH_LONG).show();
    }

    @Override
    public void rightOnClickListener() {
        Toast.makeText(this,"Clicked on the Right",Toast.LENGTH_LONG).show();
    }
}

运行结果
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CrazyMo_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值