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

365淘房APP官网下载 2025-10-29 04:21:57 阅读: 5819

文章目录

前言一、封装组件样式二、include标签+layout布局文件封装组件三、自定义组件1、复合组件(继承布局)2、修改现有组件(继承某个基础组件)3、完全自定义组件(继承View或ViewGroup)

前言

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

一、封装组件样式

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

layout布局文件:

style="@style/line"

/>

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

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

封装的layout布局文件:

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">

android:id="@+id/iv_back"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:src="@mipmap/back"

android:layout_gravity="center_vertical"/>

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"/>

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"/>

使用封装的组件:

三、自定义组件

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

自定义组件的步骤:

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

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

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

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

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">

android:id="@+id/iv_icon"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:src="@mipmap/phone"/>

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"

/>

组件的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中创建自定义组件属性):

组件效果(自定义输入框):

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;

}

}

组件的使用:

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);

}

}

组件的使用:

android:layout_width="wrap_content"

android:layout_height="wrap_content"

app:textColor="@color/mainColorH"

app:textSize="20dp"

app:text="我的自定义组件"

/>

效果图: