深入浅出安卓中封装组件的三种方法

2 篇文章 0 订阅
本文详细介绍了安卓开发中组件的封装方法,包括样式封装、使用include标签和layout布局文件、自定义组件的三种方式。自定义组件涉及复合组件、修改现有组件和完全自定义组件,通过实例展示了如何提高开发效率和灵活性。
摘要由CSDN通过智能技术生成


前言

在大前端中,有一些组件常常需要在不同的地方多次使用,但不可能在每一个地方都重新编写组件代码,因此组件的封装就显得格外重要。本篇文章将讲解安卓中封装组件的三种方法,提高读者的组件封装能力。


一、封装组件样式

这种方法是安卓中封装组件最简单的方法,将组件的样式抽离出来,单独写在styles文件里面,layout布局中直接引入样式即可。


在这里插入图片描述
styles文件:

<resources>

    <!--分割线-->
    <style name="line">
        <item name="android:layout_height">1dp</item>
        <item name="android:layout_width">match_parent</item>
        <item name="android:background">@color/lineColor</item>
        <item name="android:layout_margin">@dimen/marginSize</item>
    </style>

</resources>

layout布局文件:

<View
    	style="@style/line"
    />


二、include标签+layout布局文件封装组件

创建一个新的layout布局文件,把需要封装的组件代码编写在layout布局文件中,在需要复用组件的地方,通过include标签直接引入。

封装的layout布局文件:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="@dimen/navBarHeight"
    android:background="@color/mainColor"
    android:paddingLeft="@dimen/marginSize"
    android:paddingRight="@dimen/marginSize">

    <ImageView
        android:id="@+id/iv_back"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/back"
        android:layout_gravity="center_vertical"/>

    <TextView
        android:id="@+id/tv_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="@dimen/navBarTitleSize"
        android:textColor="@android:color/white"
        android:text="慕课音乐"
        android:layout_gravity="center"/>

    <ImageView
        android:id="@+id/iv_me"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/me"
        android:layout_gravity="right|center_vertical"/>

</FrameLayout>

使用封装的组件:

<include layout="@layout/nav_bar"/>


三、自定义组件

在安卓开发中,虽然官方提供了大量的基础组件,但是在实际开发中,常常因为业务需求的制定化而出现组件不够用的情况,因此安卓官方提供了自定义组件的方法,让开发者可以根据特殊的业务需求制定特殊化的组件,提高了开发的灵活性。

自定义组件的步骤:

  1. 创建布局文件,书写组件代码。
  2. 创建复合组件的java类,并继承某个组件、布局、View或ViewGroup.
  3. 在构造函数中,首先需要调用父类的构造函数,然后才能继续自定义的一些操作。
  4. 可以创建一些事件监听器,从而监听某个用户操作。
  5. 还可以重写一些onXxx()事件监听器,完成特殊化的业务需求。
  6. 可以自定义组件属性,充分体现出自定义组件的灵活性。
  7. 重写onMeasure()、onDraw()等方法,这两个方法主要是实现组件的渲染,确定组件的大小及显示的内容,默认大小为100x100。(注意:如果第2步继承布局,那么则不需要重写,因为布局中有定义好的特性,不需要更改。)

在自定义组件中,分为以下三种场景:

1、复合组件(继承布局)

由多个基础组件(安卓官方提供的组件)组合而成的组件被称为复合组件。
组件的XML布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="@dimen/inputViewHeight"
    android:orientation="horizontal"
    android:gravity="center_vertical"
    android:paddingLeft="@dimen/marginSize"
    android:paddingRight="@dimen/marginSize">

    <ImageView
        android:id="@+id/iv_icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/phone"/>

    <EditText
        android:id="@+id/et_input"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@null"
        android:hint="用户名"
        android:paddingLeft="@dimen/marginSize"
        android:paddingRight="@dimen/marginSize"
        android:textSize="@dimen/titleSize"
        />

</LinearLayout>

组件的java类:

package com.sunday.imoocmusicdemo.views;

import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.text.InputType;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AbsoluteLayout;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;

import com.sunday.imoocmusicdemo.R;

/**
 * 1、input_icon:输入框前面的图标
 * 2、input_hint: 输入框的提示内容
 * 3、is_password: 输入的内容是否需要以密文的形式展示
 */
public class InputView extends FrameLayout {

    private int inputIcon;
    private String inputHint;
    private boolean isPassword;

    private View mView;
    private ImageView mIvIcon;
    private EditText mEtInput;

    // 创建组件的构造方法
    public InputView(@NonNull Context context) {
        super(context);
        init(context, null);
    }

    public InputView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public InputView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public InputView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context, attrs);
    }

    /**
     * 初始化方法
     */
    private void init (Context context, AttributeSet attrs) {
        if (attrs == null) return;
//        获取自定义属性
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.inputView);
        inputIcon = typedArray.getResourceId(R.styleable.inputView_input_icon, R.mipmap.logo);
        inputHint = typedArray.getString(R.styleable.inputView_input_hint);
        isPassword = typedArray.getBoolean(R.styleable.inputView_is_password, false);
        typedArray.recycle();

//        绑定layout布局
        mView = LayoutInflater.from(context).inflate(R.layout.input_view, this, false);
        mIvIcon = mView.findViewById(R.id.iv_icon);
        mEtInput = mView.findViewById(R.id.et_input);

//        布局关联属性
        mIvIcon.setImageResource(inputIcon);
        mEtInput.setHint(inputHint);
        mEtInput.setInputType(isPassword ? InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD : InputType.TYPE_CLASS_PHONE);

        addView(mView);
    }

    /**
     * 返回输入的内容
     * @return
     */
    public String getInputStr () {
        return mEtInput.getText().toString().trim();
    }
}

自定义组件属性(在res/values/attrs.xml中创建自定义组件属性):

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

    <!--声明样式-->
    <declare-styleable name="inputView">
        <!--输入框前面的小图标-->
        <attr name="input_icon" format="reference"></attr>
        <!--输入框提示内容-->
        <attr name="input_hint" format="string"></attr>
        <!--输入框是否需要以密文展示-->
        <attr name="is_password" format="boolean"></attr>
    </declare-styleable>

</resources>

组件效果(自定义输入框):
在这里插入图片描述


2、修改现有组件(继承某个基础组件)

       继承安卓官方提供的基础组件,更改或完善基础组件的特性。
组件的java类:

package com.sunday.imoocmusicdemo.views;

import android.content.Context;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnFocusChangeListener;
import android.view.View.OnTouchListener;
import android.widget.ImageButton;
import android.annotation.SuppressLint;
@SuppressLint("AppCompatCustomView")

/**
 * 自定义图片按钮(ImageButton),按下颜色改变
 * @author Leo
 * @created 2013-3-15
 */
public class CmButton extends ImageButton implements OnTouchListener, OnFocusChangeListener {

    public CmButton(Context context) {
        super(context);
        this.setOnTouchListener(this);
        this.setOnFocusChangeListener(this);
    }

    public CmButton(Context context, AttributeSet attrs) {
        this(context, attrs, android.R.attr.imageButtonStyle);
        this.setOnTouchListener(this);
        this.setOnFocusChangeListener(this);
    }

    public CmButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setFocusable(true);
        this.setOnTouchListener(this);
        this.setOnFocusChangeListener(this);
    }

    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        // 灰色效果
        ColorMatrix cm = new ColorMatrix();
        cm.setSaturation(0);
        if (hasFocus) {
            ((ImageButton) v).getDrawable().setColorFilter(new ColorMatrixColorFilter(cm));
        } else {
            ((ImageButton) v).getDrawable().clearColorFilter();
        }
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        // 灰色效果
        ColorMatrix cm = new ColorMatrix();
        cm.setSaturation(0);
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            ((ImageButton) v).getDrawable().setColorFilter(new ColorMatrixColorFilter(cm));
        } else if (event.getAction() == MotionEvent.ACTION_UP) {
            ((ImageButton) v).getDrawable().clearColorFilter();
        }
        return false;
    }
}

组件的使用:

<com.sunday.imoocmusicdemo.views.CmButton
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_gravity="center"
        android:background="#00000000"
        android:src="@mipmap/button_img"
        android:text="登录" />

组件效果:
在这里插入图片描述



3、完全自定义组件(继承View或ViewGroup)

       继承View或ViewGroup,重写onMeasure()、onDraw()方法,创建属于你的专属组件。

组件的java类:

package com.sunday.imoocmusicdemo.views;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Paint.Style;
import android.util.AttributeSet;
import com.sunday.imoocmusicdemo.R;
import android.view.View;
public class MyView extends View {
    private Paint mPaint;
    private Context mContext;
    private String mString;

    public MyView(Context context) {
        super(context);
        mPaint = new Paint();
    }
    public MyView(Context context,AttributeSet attrs)
    {
        super(context,attrs);
        mPaint = new Paint();

        TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.MyView);

        int textColor = a.getColor(R.styleable.MyView_textColor,
                0XFFFFFFFF);
        float textSize = a.getDimension(R.styleable.MyView_textSize, 36);
        mString = a.getString(R.styleable.MyView_text);

        mPaint.setTextSize(textSize);
        mPaint.setColor(textColor);

        a.recycle();
    }
    @Override
    protected void onDraw(Canvas canvas) {
        // TODO Auto-generated method stub
        super.onDraw(canvas);
        //设置填充
        mPaint.setStyle(Style.FILL);

        //画一个矩形,前俩个是矩形左上角坐标,后面俩个是右下角坐标
        canvas.drawRect(new Rect(300, 10, 800, 200), mPaint);

        mPaint.setColor(Color.BLACK);
        //绘制文字
        canvas.drawText(mString, 340, 110, mPaint);
    }
}

组件的使用:

    <com.sunday.imoocmusicdemo.views.MyView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:textColor="@color/mainColorH"
        app:textSize="20dp"
        app:text="我的自定义组件"
        />

效果图:
在这里插入图片描述



  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值