一、前言

        最近做一个项目又一次用到类似像微信一样的标题栏,之前就实现过一次,但是几个月没有用了,就忘记了,导致这次再次使用却调了大半天才完成。因此,写下这篇文章记录下来,同时再一次巩固自己的理解。

        这回使用的Android的自定义控件中的组合控件。

二、自定义组合控件原理

        项目中经常会遇见很多相似或者相同的布局,比如APP的标题栏,通过将这些布局抽取出来,放到一个独立的布局中,封装成独立一个类中做管理,作为单独的一个控件。当再次需要时,即可将其添加到布局文件中,实现复用,提高开发效率,降低了开发成本。

三、步骤

3.1 以下图为例,实现一个仿微信的标题栏。


3.2 一般的步骤是  

a. 将需要实现的自定义控件的布局风封装一个单独的xml 布局文件。

b. 通过一个继承一个ViewGroup 类,然后加载自定义布局文件。

c. 设置定义控件的属性。

d. 实现一些方法和提供一些接口供用户使用。


四、举例,仿微信标题栏。

4.1 运行环境,Android studio 3.0     安卓模拟器

4.2. 在工程的res/layout目录新建自定义控件的布局文件 activity_title_view_for_back_and_add.xml,如下图:

4.3 在工程目录下,新建自定义控件类 ActivityTitleViewForBackAndAdd.java,继承自ViewGroup -> Relativelayout, 如下图。


布局代码如下:

<?xml version="1.0" encoding="utf-8"?>                

4.4 新建类代码如下:

public class ActivityTitleViewForBackAndAdd extends RelativeLayout{    private static final String TAG = ActivityTitleViewForBackAndAdd.class.getSimpleName();    private final String mNameSpace = "http://schemas.android.com/apk/res/chen.chenximobilesafe";    public ActivityTitleViewForBackAndAdd(Context context)    {        this(context, null);//调用同名构造方法    }    public ActivityTitleViewForBackAndAdd(Context context, AttributeSet attributeSet)    {        this(context, attributeSet, 0); //调用同名构造方法    }    public ActivityTitleViewForBackAndAdd(Context context, AttributeSet attributeSet, int defaultStyle)    {//通过上面的传参,实现无论系统调用,哪个构造方法,最终调用的是具有样式的构造方法        super(context, attributeSet, defaultStyle);}}

4.5 在第三个构造方法中,使用打气筒Inflate创建view 对象。

代码如下:

  public ActivityTitleViewForBackAndAdd(Context context, AttributeSet attributeSet, int defaultStyle)    {        super(context, attributeSet, defaultStyle);        //将打气筒根据自定义控件的布局文件,创建的view 对象挂载到当前类上面,然后显示        View view = (View) View.inflate(context, R.layout.activity_title_view_for_back_and_add, this);        mTvTitle = (TextView) view.findViewById(R.id.tv_title_view_tile2);        mIvBtnBack = (ImageView) view.findViewById(R.id.iv_title_back2);        mIvBtnAdd = (ImageView) view.findViewById(R.id.iv_title_add);        //初始化相关自定义属性        initStyle(attributeSet);}

上面的原理是,如下图:


4.6 添加自定义属性

自定义属性一般在attrs.xml文件中定义,因此,需要在工程的res/values目录下创建一个attrs.xml,如下图:


由于的标题栏比较简单,只需增加标题的设置功能就可以,因此,增加一个属性即可,格式如下:

<?xml version="1.0" encoding="utf-8"?>    >        >    

4.7 在自定义控件类的构造方法中,获取定义属性值,并赋值。

方法如下,

 private void initStyle(AttributeSet attributeSet) {     mTvTitle.setText(attributeSet.getAttributeValue(mNameSpace, "text1")); }

4.8 增加相关接口和方法,标题栏中,主要用于退出操作和增加操作,因此,只需提供两个接口即可。

在完整代码如下:

package chen.control;import android.content.Context;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.view.View;import android.widget.ImageView;import android.widget.RelativeLayout;import android.widget.TextView;import chen.chenximobilesafe.R;/** * Created by 69009 on 2018/2/17. */public class ActivityTitleViewForBackAndAdd extends RelativeLayout{    private static final String TAG = ActivityTitleViewForBackAndAdd.class.getSimpleName();    private TextView mTvTitle = null;    private ImageView mIvBtnBack = null, mIvBtnAdd = null;    //命名空间    private final String mNameSpace = "http://schemas.android.com/apk/res/chen.chenximobilesafe";    //退出按钮点击事件监听对象    private OnBackItemClickListener mOnItemClickListener = null;    //增加按钮点击事件监听对象    private OnAddItemClickListener mOnAddItemClickListener = null;    public ActivityTitleViewForBackAndAdd(Context context)    {        this(context, null);    }    public ActivityTitleViewForBackAndAdd(Context context, AttributeSet attributeSet)    {        this(context, attributeSet, 0);    }    public ActivityTitleViewForBackAndAdd(Context context, AttributeSet attributeSet, int defaultStyle)    {        super(context, attributeSet, defaultStyle);        //将打气筒根据自定义控件的布局文件,创建的view 对象挂载到当前类上面,然后显示        View view = (View) View.inflate(context, R.layout.activity_title_view_for_back_and_add, this);        //获取子控件对象        mTvTitle = (TextView) view.findViewById(R.id.tv_title_view_tile2);        mIvBtnBack = (ImageView) view.findViewById(R.id.iv_title_back2);        mIvBtnAdd = (ImageView) view.findViewById(R.id.iv_title_add);        initStyle(attributeSet);        //注册系统点击事件        mIvBtnBack.setOnClickListener(mIamgeViewBtnOnClickListener);        mIvBtnAdd.setOnClickListener(mIamgeViewBtnOnClickListener);        //点击退出按钮时,切换背景        mIvBtnBack.setOnTouchListener(new OnTouchListener()        {            @Override            public boolean onTouch(View v, MotionEvent event)            {                switch (event.getAction())                {                    case MotionEvent.ACTION_UP:                        mIvBtnBack.setImageResource(R.drawable.fx_icon_back_n);                        break;                    case MotionEvent.ACTION_DOWN:                        mIvBtnBack.setImageResource(R.drawable.fx_icon_back_p);                        break;                }                return false;            }        });    }    private void initStyle(AttributeSet attributeSet)    {        mTvTitle.setText(attributeSet.getAttributeValue(mNameSpace, "text1"));    }    //注册点击事件    public void setBackItemClickListener(OnBackItemClickListener listener)    {        mOnItemClickListener = listener;    }        //注册点击事件    public void setAddItemClickListener(OnAddItemClickListener listener)    {        mOnAddItemClickListener = listener;    }    //提供两个接口,通过回调机制,实现用户自定义退出按钮和增加按钮的点击事件    public interface OnBackItemClickListener    {        void onClick();    }    public interface OnAddItemClickListener    {        void onClick();    }    private OnClickListener mIamgeViewBtnOnClickListener = new OnClickListener()    {        @Override        public void onClick(View view)        {            Log.d(TAG, "进入 onclick");            switch(view.getId())            {                case R.id.iv_title_add:                    if(mOnAddItemClickListener != null)                        mOnAddItemClickListener.onClick();                    break;                case R.id.iv_title_back2:                    if(mOnItemClickListener != null)                        mOnItemClickListener.onClick();                break;            }        }    };}

4.9 在布局文件中使用定义控件,使用定义控件需要使用自定义类的全完整类名,并且使用自定义属性

需要定义自己的命令空间,代码如下:

<?xml version="1.0" encoding="utf-8"?>            xmlns:custom="http://schemas.android.com/apk/res/chen.chenximobilesafe"            android:id="@+id/title_back_blacklist"        android:layout_width="match_parent"        android:layout_height="wrap_content"        custom:text1="黑名单管理"            >        

4.10 在类中获取自动定义控件对象,并且增加注册自定义监听事件,代码如下:

public class BlackListNumberActivity extends AppCompatActivity{    private static final String TAG = BlackListNumberActivity.class.getSimpleName();    private ActivityTitleViewForBackAndAdd mTitle = null;    private android.support.v7.app.AlertDialog mDialog = null;    private Button    @Override    public void onCreate(Bundle saveInstanceState)    {        super.onCreate(saveInstanceState);        setContentView(R.layout.activity_blacklist_number);        initUI();    }    private void initUI()    {        mTitle = (ActivityTitleViewForBackAndAdd)findViewById(R.id.title_back_blacklist);        mTitle.setBackItemClickListener(new ActivityTitleViewForBackAndAdd.OnBackItemClickListener()        {            @Override            public void onClick()            {                finish();            }        });        mTitle.setAddItemClickListener(new ActivityTitleViewForBackAndAdd.OnAddItemClickListener()        {            @Override            public void onClick()            {                if(mDialog == null)                {                    AlertDialog.Builder builder = new AlertDialog.Builder(BlackListNumberActivity.this);                    View view = View.inflate(BlackListNumberActivity.this, R.layout.black_list_number_dialog_view, null);                    mDialog = builder.create();                    mDialog.setView(view);                }                mDialog.show();            }        });    }}

好了,自定义组合控件大概记录这么多,方便下次忘记了,还可以再看。

通过这次,非常体会到“好记忆不如烂笔头”这句谚语的意思了。

更多相关文章

  1. 【Android】关于百分比布局多个LinearLayout嵌套时出现的问题与
  2. 关于android混合开发模式Hybrid逻辑梳理
  3. Android百分比布局支持库(android-percent-support)
  4. Android----xml文件中的控件的id设置
  5. 成佩涛编程之路——Android控件动画效果(二)
  6. Android(安卓)仿当乐游戏详情页面(二)
  7. 用Carbide C++ UI Designer做UI的爽与不爽
  8. Activity布局初步 RelativieLayout相对布局
  9. Android中去掉或更改标题栏TitleBar,theme的更改

随机推荐

  1. Android 自定义布局对话框避免全屏的设置
  2. Android设备内存和SD卡操作工具类
  3. 【Android-Activity】EditText的基本属性
  4. Android各个版本对应的源代码
  5. Android(安卓)Widget开发系列(二)
  6. android N 编译环境搭建
  7. 鸿蒙开发TV软件环境搭建以及简单教程
  8. android程序执行adb shell命令
  9. 详解Android(安卓)App AllowBackup配置带
  10. android使用util工具包