自定义组合控件就是多个控件组合起来成为一个新的控件,用来解决多次重复的使用同一类型的布局,比如对话框、APP的标题栏等。这里列举一个最近项目开发中自定义的组合控件。
先看做好的效果:
自定义的选择按钮
按钮选中的样式:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="3dp" />
<solid android:color="@color/white" />
<stroke
android:width="1dp"
android:color="#2d6fff" />
</shape>
按钮未选中时候的样式:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="3dp" />
<solid android:color="@color/white" />
<stroke
android:width="1dp"
android:color="#dcdcdc" />
</shape>
样式布局:
右下角的打钩样式以及文字提示
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/mImg"
android:layout_width="15dp"
android:layout_height="15dp"
android:scaleType="fitXY"
android:src="@drawable/selected_radio"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<TextView
android:id="@+id/mTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
自定义属性:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MarkRadioButton">
<attr name="textSize" format="integer" />
<attr name="text" format="string"/>
</declare-styleable>
</resources>
具体实现:
package cn.zzw.composeview.custom.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import cn.zzw.composeview.R;
/**
* @author 鹭岛猥琐男
* @create 2019/10/2 22:59
*/
public class MarkRadioButton extends LinearLayout {
private boolean checked;
private TextView mTv;
private ImageView mImg;
private View mRootView;
private Drawable mDrawableUnChecked;
private Drawable mDrawableChecked;
public MarkRadioButton(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
initView(context);
/* 获取自定义的属性*/
TypedArray typedArray = getContext()
.obtainStyledAttributes(attrs, R.styleable.MarkRadioButton);
if (null != typedArray) {
int textSize = typedArray.getInt(R.styleable.MarkRadioButton_textSize, 0);
String text = typedArray.getString(R.styleable.MarkRadioButton_text);
mTv.setTextSize(TypedValue.COMPLEX_UNIT_SP, textSize);
mTv.setText(text);
}
}
private void initView(Context context) {
mRootView = LayoutInflater.from(getContext()).inflate
(R.layout.layout_mark_radiobutton, this);
mTv = mRootView.findViewById(R.id.mTv);
mImg = mRootView.findViewById(R.id.mImg);
mDrawableUnChecked = context.getResources().getDrawable
(R.drawable.bg_mark_radiobutton_unchecked);
mDrawableChecked = context.getResources().getDrawable
(R.drawable.bg_mark_radiobutton_checked);
}
/**
* 设置选择状态
*/
public void setChecked(boolean checked) {
this.checked = checked;
if (this.checked) {
mImg.setVisibility(VISIBLE);
mRootView.setBackground(mDrawableChecked);
mTv.setTextColor(Color.parseColor("#2d6fff"));
} else {
mTv.setTextColor(Color.parseColor("#666666"));
mImg.setVisibility(GONE);
mRootView.setBackground(mDrawableUnChecked);
}
invalidate();
}
}
自定义对话框实现:
自定义对话框的风格:
<!-- Dialog -->
<style name="base_dialog" parent="android:Theme.Dialog">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowCloseOnTouchOutside">true</item>
</style>
对话框的布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/dialog_bg"
android:splitMotionEvents="false"
android:orientation="vertical">
<LinearLayout
android:layout_width="327dp"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="43dp"
android:gravity="center"
android:text="性别选择"
android:textColor="#444444"
android:textSize="16sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#dddddd" />
<TextView
android:id="@+id/mMsg_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="12dp"
android:text="请选择性别"
android:textColor="#8E8D8D"
android:textSize="16sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="5dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_horizontal"
>
<cn.zzw.composeview.custom.view.MarkRadioButton
android:id="@+id/mRbLeft"
android:layout_width="132dp"
android:layout_height="50dp"
app:text="男"
app:textSize="16"></cn.zzw.composeview.custom.view.MarkRadioButton>
<TextView
android:layout_width="31dp"
android:layout_height="wrap_content"/>
<cn.zzw.composeview.custom.view.MarkRadioButton
android:id="@+id/mRbRight"
android:layout_width="132dp"
android:layout_height="50dp"
app:text="女"
app:textSize="16"></cn.zzw.composeview.custom.view.MarkRadioButton>
</LinearLayout>
<TextView
android:layout_width="29dp"
android:layout_height="29dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#dddddd" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_gravity="bottom"
android:orientation="horizontal">
<TextView
android:id="@+id/mBtnCancel"
android:layout_width="0dp"
android:layout_weight="1"
android:textSize="16sp"
android:gravity="center"
android:text="取消"
android:textColor="#8E8D8D"
android:layout_height="match_parent"/>
<TextView
android:layout_width="1dp"
android:layout_height="match_parent"
android:background="#dddddd"/>
<TextView
android:id="@+id/mBtnConfirm"
android:layout_width="0dp"
android:layout_weight="1"
android:textSize="16sp"
android:gravity="center"
android:text="确定"
android:textColor="#F15E61"
android:layout_height="match_parent"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
对话框的实现:
package cn.zzw.composeview.custom.dialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.view.LayoutInflater;
import android.view.View;
import androidx.annotation.NonNull;
import cn.zzw.composeview.R;
import cn.zzw.composeview.custom.view.MarkRadioButton;
/**
* @author 鹭岛猥琐男
* @create 2019/10/2 23:09
*/
public class SelectDialog extends Dialog implements
View.OnClickListener, DialogInterface.OnDismissListener {
private MarkRadioButton mRbLeft;
private MarkRadioButton mRbRight;
private View mBtnCancel;
private View mBtnConfirm;
private int mCheckedIndex;// 在点击确认取消按钮的时候,返回当前选中哪个按钮(从左到右,从0开始)
private boolean mRbLeftIsChecked = true;
private boolean mRbRightIsChecked = !mRbLeftIsChecked;
private IDialogButtonClickListener mListener;
public SelectDialog(@NonNull Context context) {
this(context, R.style.base_dialog);
}
public SelectDialog(@NonNull Context context, int themeResId) {
super(context, themeResId);
init();
}
private void init() {
View view = LayoutInflater.from(getContext()).inflate(R.layout.dialog_select,
null);
setContentView(view);
mRbLeft = view.findViewById(R.id.mRbLeft);
mRbLeft.setChecked(true);
mRbRight = view.findViewById(R.id.mRbRight);
mRbRight.setChecked(false);
mRbLeft.setOnClickListener(this);
mRbRight.setOnClickListener(this);
mBtnCancel = view.findViewById(R.id.mBtnCancel);
mBtnConfirm = view.findViewById(R.id.mBtnConfirm);
mBtnCancel.setOnClickListener(this);
mBtnConfirm.setOnClickListener(this);
}
public void setOnDialogButtonClickListener(IDialogButtonClickListener listener) {
this.mListener = listener;
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.mRbLeft:
if (!mRbLeftIsChecked) {
mRbLeftIsChecked = true;
mRbLeft.setChecked(true);
mRbRight.setChecked(!mRbLeftIsChecked);
mCheckedIndex = 0;
}
break;
case R.id.mRbRight:
if (mRbLeftIsChecked) {
mRbLeftIsChecked = false;
mRbLeft.setChecked(false);
mRbRight.setChecked(!mRbLeftIsChecked);
mCheckedIndex = 1;
}
break;
case R.id.mBtnCancel:
if (null != mListener) {
mListener.leftButtonClick(mCheckedIndex);
}
dismiss();
break;
case R.id.mBtnConfirm:
if (null != mListener) {
mListener.RightButtonClick(mCheckedIndex);
}
dismiss();
break;
}
}
@Override
public void onDismiss(DialogInterface dialog) {
if (mListener != null) {
mListener.onDialogDissmiss();
}
}
/* 对话框的接口*/
public interface IDialogButtonClickListener {
void leftButtonClick(int mCheckedIndex);
void onDialogDissmiss();
void RightButtonClick(int mCheckedIndex);
}
}
调用对话框:
package cn.zzw.composeview;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import cn.zzw.composeview.custom.dialog.SelectDialog;
public class MainActivity extends AppCompatActivity implements SelectDialog.IDialogButtonClickListener {
private SelectDialog mDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.mBtnDialog).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (null == mDialog) {
mDialog = new SelectDialog(MainActivity.this);
mDialog.setOnDialogButtonClickListener(MainActivity.this);
}
if (!mDialog.isShowing()) {
mDialog.show();
}
}
});
}
@Override
public void leftButtonClick(int mCheckedIndex) {
Toast.makeText(this, "选中按钮的下标: " + mCheckedIndex, Toast.LENGTH_SHORT).show();
mDialog = null;
}
@Override
public void onDialogDissmiss() {
mDialog = null;
}
@Override
public void RightButtonClick(int mCheckedIndex) {
Toast.makeText(this, "选中按钮的下标: " + mCheckedIndex, Toast.LENGTH_SHORT).show();
mDialog = null;
}
}