具有自定义属性的自定义控件
自定义的属性
在values文件夹下新建一个attrs.xml文件,在其中定义一个新的样式,在样式下的子标签中放入一些自己所需的属性。
format表示能接受哪些内容, reference是指资源文件
<?xml version="1.0" encoding="utf-8"?>
<!--自定义的属性-->
<resources>
<!-- 声明一个需要的样式-->
<!-- 一个样式对应着一个控件-->
<!--一个叫InputView的样式,该样式还具备一些属性 -->
<declare-styleable name="InputView">
<!-- 输入框前面的小图标 -->
<attr name="input_icon" format="reference"/>
<!--输入框的提示内容 -->
<attr name="input_hint" format="string"></attr>
<!-- 输入框的内容是否以密文进行展示-->
<attr name="is_password" format="boolean"></attr>
</declare-styleable>
</resources>
新建一个布局文件
写入自己所需要的一些布局。
一些数据都存放在dimen的xml文件中,方便统一更改。
<?xml version="1.0" encoding="utf-8"?>
<!--用来存储各种尺寸数据-->
<!--一个dimen标签对应于一个数据,如果标签中还有子标签,子标签是表明性质之类的东西-->
<resources>
<dimen name="marginSize">16dp</dimen>
<dimen name="navBarHeight">56dp</dimen>
<dimen name="navBarTitleSize">22sp</dimen>
<dimen name="titleSize">18sp</dimen>
<dimen name="inputViewHeight">44dp</dimen>
</resources>
<?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:layout_gravity="center_vertical"
android:paddingRight="@dimen/marginSize"
android:paddingLeft="@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:paddingLeft="@dimen/marginSize"
android:paddingRight="@dimen/marginSize"
android:hint="用户名"
android:textSize="@dimen/titleSize"/>
</LinearLayout>
新建一个类
1.该类必须继承自某一基础布局,并且重写构造器。
2.在每个构造器中都要执行init()。
3.initi()函数有三个功能:1.获取自定义属性,2.加载之前布局 3.给布局中的控件绑定属性4.将加载的布局加入到该类的子View中
private int inputIcon;//null
private String inputHint;
private boolean isPassword;
private View mView;
private EditText mEtInput;
private ImageView mIvIcon;
// 使用inputView布局时,可以通过 AttributeSet 来获取我们所传入的属性。
private void init(Context context, AttributeSet attrs){
if (attrs == null) return;
//获取自定义属性 R.styleable.InputView表明属性来源
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.InputView);
// getxxxxx是由format决定的。
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();
// 绑定布局
mView = LayoutInflater.from(context).inflate(R.layout.input_view,this, false);
mEtInput = mView.findViewById(R.id.et_input);
mIvIcon = mView.findViewById(R.id.iv_icon);
// 布局关联属性
mIvIcon.setImageResource(inputIcon);
mEtInput.setHint(inputHint);
//设置是否密文展示 是 InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD 来表示密文
// 否 接收手机号的输入 InputType.TYPE_CLASS_PHONE
mEtInput.setInputType(isPassword ? InputType.TYPE_CLASS_TEXT | InputType.TYPE_NUMBER_VARIATION_PASSWORD
: InputType.TYPE_CLASS_PHONE);
// 将mView添加到InPutView--将inputView 的布局 与mView绑定在一起了
addView(mView);
}
4.其他一些需求的功能方法。
/**
* 返回输入内容
* @return
*/
public String getInputStr(){
return mEtInput.getText().toString().trim();
}
在其他布局文件中使用该控件
自己定义的属性前缀是app.
<com.example.musicclouddemo.views.InputView
android:layout_width="match_parent"
android:layout_height="@dimen/inputViewHeight"
android:layout_marginTop="@dimen/marginSize"
app:input_icon="@mipmap/phone"
app:input_hint="手机号"
app:is_password="false"/>
完整的inputView代码
package com.example.musicclouddemo.views;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
import android.text.InputType;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.example.musicclouddemo.R;
/**需要3个可配置的属性
* 1.input_icon:输入框前面的图标
* 2.input_hint : 输入框的提示内容
* 3. is_passWord :输入框的内容是否以密文进行展示。
* Ctreate by barry on 2020/10/7.
*/
public class InputView extends FrameLayout {
private int inputIcon;//null
private String inputHint;
private boolean isPassword;
private View mView;
private EditText mEtInput;
private ImageView mIvIcon;
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);
}
// 使用inputView布局时,可以通过 AttributeSet 来获取我们所传入的属性。
private void init(Context context, AttributeSet attrs){
if (attrs == null) return;
//获取自定义属性 R.styleable.InputView表明属性来源
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.InputView);
// getxxxxx是由format决定的。
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();
// 绑定布局
mView = LayoutInflater.from(context).inflate(R.layout.input_view,this, false);
mEtInput = mView.findViewById(R.id.et_input);
mIvIcon = mView.findViewById(R.id.iv_icon);
// 布局关联属性
mIvIcon.setImageResource(inputIcon);
mEtInput.setHint(inputHint);
//设置是否密文展示 是 InputType.TYPE_CLASS_TEXT | InputType.TYPE_NUMBER_VARIATION_PASSWORD 来表示密文
// 否 接收手机号的输入 InputType.TYPE_CLASS_PHONE
mEtInput.setInputType(isPassword ? InputType.TYPE_CLASS_TEXT | InputType.TYPE_NUMBER_VARIATION_PASSWORD
: InputType.TYPE_CLASS_PHONE);
// 将mView添加到InPutView--将inputView 的布局 与mView绑定在一起了
addView(mView);
}
/**
* 返回输入内容
* @return
*/
public String getInputStr(){
return mEtInput.getText().toString().trim();
}
}