安卓中组件的复用与封装
最近在刷线上课程,进度缓慢。跟着教程能慢慢理解,但是轮到自己单独完成困难重重。尝试一下写下来帮助记忆与理解;
include标签引入共用Layout + 在BaseActivity创建配置方法
首先分析你的布局中可以复用的组件,把组件单独分离出来,创建一个Layout布局;如本例中的NaviationBar;在多个页面都会存在NaviationBar,哪就把他单独写一个布局,利用
<include layout="@layout/nav_bar">
在多个Activity的布局文件中进行引用;
如果该布局在不同的页面稍有不同,可以在BaseActivity中创建一个公共方法,方便在不同的Activity中对navBar进行配置;
1.在 res -> Layout 下新建一个layout nav_bar.xml
<?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="match_parent"
android:src="@mipmap/back"/>
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="云音乐"
android:textColor="@color/white"
android:textSize="@dimen/navBarTitleSize"
android:layout_gravity="center"
android:shadowColor="@color/mainColor"
android:shadowDy="1"
android:shadowRadius="3"/>
<ImageView
android:id="@+id/iv_mine"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/mine"
android:layout_gravity="end|center_vertical"/>
</FrameLayout>
2.在布局中引入nav_bar
<include layout="@layout/nav_bar">
3.在BaseActivity中创建方法用于配置每个Activity中nav_bar的不同状态
/*初始化*/
protected void initNavBar(boolean isShowback, String title, boolean isShowmine) {
tv_title = findViewById(R.id.tv_title);
iv_back = findViewById(R.id.iv_back);
iv_mine = findViewByIdR.id.iv_mine);
tv_title.setText(title);
iv_back.setVisibility(isShowback ? View.VISIBLE : View.GONE);
iv_mine.setVisibility(isShowmine ? View.VISIBLE : View.GONE);
}
自定义View的方式封装复用组件
1.在 res -> values -> attrs (没有则新建) 申明可设计样式“inputBox”
<resources>
<!--声明可设计样式-->
<declare-styleable name="inputBox">
<!--声明图标样式,接收的是资源文件-->
<attr name="input_icon" format="reference"></attr>
<!--声明提示文字,为字符串类型-->
<attr name="input_hint" format="string"></attr>
<!--声明是否以密文展示-->
<attr name="isPassWord" format="boolean"></attr>
</declare-styleable>
</resources>
2. res -> layout 创建组件的布局文件 input_box.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="match_parent"
android:paddingLeft="@dimen/marginSize"
android:paddingRight="@dimen/marginSize">
<ImageView
android:id="@+id/iv_icon"
android:layout_width="@dimen/inputBoxHeiht"
android:layout_height="@dimen/inputBoxHeiht"
android:src="@mipmap/mine" />
<EditText
android:id="@+id/et_inputText"
android:layout_width="match_parent"
android:layout_height="@dimen/inputBoxHeiht"
android:hint="手机号"
android:textSize="@dimen/inputTextSize"
android:layout_marginLeft="@dimen/marginSize"
android:background="@null"/>
</LinearLayout>
3.创建InputView类,将上面的布局和自定义属性关联封装成组件
public class InputView extends FrameLayout {
private int inputIcon;
private String inputHint;
private Boolean isPassWord;
private View mView;
private ImageView mInputIcon;
private EditText editText;
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;}
// 获取自定义的属性 留意一下自定义属性的id是:
// “R.styleable.” +自定义样式Name + “_” + 自定义属性Name
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.inputBox);
inputIcon = typedArray.getResourceId(R.styleable.inputBox_input_icon,R.mipmap.logo);
inputHint = typedArray.getString(R.styleable.inputBox_input_hint);
isPassWord = typedArray.getBoolean(R.styleable.inputBox_isPassWord,false);
typedArray.recycle();
//绑定Layout布局
mView = LayoutInflater.from(context).inflate(R.layout.input_box,this,false);
mInputIcon = mView.findViewById(R.id.iv_icon);
editText = mView.findViewById(R.id.et_inputText);
//布局关联属性
mInputIcon.setImageResource(inputIcon);
editText.setHint(inputHint);
editText.setInputType(isPassWord ? InputType.TYPE_CLASS_TEXT|InputType.TYPE_NUMBER_VARIATION_PASSWORD :InputType.TYPE_CLASS_PHONE);
addView(mView);
}
public String getInputText(){
return editText.getText().toString().trim();
}
}
4.完成了上面的3步,我们就可以在布局中使用它了
注意自定义的属性前面带上 app:
就好像Android的属性带上 android: 一样
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<include layout="@layout/nav_bar"/>
<ImageView
android:layout_width="200dp"
android:layout_height="200dp"
android:src="@mipmap/logo"
android:layout_gravity="center_horizontal"
android:layout_marginTop="@dimen/marginSize"
/>
// 对封装好的InputView的使用
<com.hu.j_music.views.InputView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:input_icon="@mipmap/mine"
app:input_hint="手机号"
app:isPassWord="false"/>
</LinearLayout>
暂时了解到的就这些了。后面的那种封装自定义View的方式还没有特别掌握,对TypedArray这个类不熟悉,对context.obtainStyledAttributes(attrs, R.styleable.inputBox);方法也比较陌生。
然后加载layout布局之前接触过但是也不算熟悉;