文章目录
前言一、封装组件样式二、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="我的自定义组件" /> 效果图: