文章目录
前言
在大前端中,有一些组件常常需要在不同的地方多次使用,但不可能在每一个地方都重新编写组件代码,因此组件的封装就显得格外重要。本篇文章将讲解安卓中封装组件的三种方法,提高读者的组件封装能力。
一、封装组件样式
这种方法是安卓中封装组件最简单的方法,将组件的样式抽离出来,单独写在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"/>
三、自定义组件
在安卓开发中,虽然官方提供了大量的基础组件,但是在实际开发中,常常因为业务需求的制定化而出现组件不够用的情况,因此安卓官方提供了自定义组件的方法,让开发者可以根据特殊的业务需求制定特殊化的组件,提高了开发的灵活性。
自定义组件的步骤:
- 创建布局文件,书写组件代码。
- 创建复合组件的java类,并继承某个组件、布局、View或ViewGroup.
- 在构造函数中,首先需要调用父类的构造函数,然后才能继续自定义的一些操作。
- 可以创建一些事件监听器,从而监听某个用户操作。
- 还可以重写一些onXxx()事件监听器,完成特殊化的业务需求。
- 可以自定义组件属性,充分体现出自定义组件的灵活性。
- 重写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="我的自定义组件"
/>
效果图: