1、闲聊
- 说到组合控件,人人都会。为什么要这么说呢?可以这样说我们每一个layout布局都是你定义的组合控件,但是,当你需要实现同一种功能的时候,有N个界面都需要这种组合控件,你们可能会想了:我每次使用 “include”标签导入一下布局不就行了吗?我想说的逻辑呢?难道用CV?
2、实现方法
说说实现方法吧
- 使用xml写一个布局,然后定义一个View来加载这个布局
- 直接继承RelativeLayout、LinearLayout等布局方式,然后动态添加你所需的View
我们简单了解一下第一种吧,因为可说的是大家都会,定义一个View来加载,需要多次使用并且逻辑相同的布局,通过“findViewById”来得到子控件,并书写逻辑,这个自定义控件就基本完成了,我这里说的是第二种纯 java 代码实现。
3、实例
不BB了,我们直接上代码
public class DelInputView extends RelativeLayout implements TextWatcher, View.OnClickListener {
public DelInputView(Context context) {
super(context);
init(context);
}
public DelInputView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public DelInputView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public DelInputView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context);
}
private static final String TAG = "DelInputView";
private Context context;
private Integer delResId;
private Bitmap delBitmap;
private EditText editText;
private ImageView imageView;
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void init(Context context) {
this.context = context;
editText = new EditText(context);
LayoutParams lp = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
editText.setLayoutParams(lp);
editText.setBackground(null);
addView(editText);
editText.addTextChangedListener(this);
if (null == getBackground()) {
int left = getPaddingLeft();
int top = getPaddingTop();
int right = getPaddingRight();
int bottom = getPaddingBottom();
setBackgroundResource(R.drawable.delinputview);
// 这里调用了setBackgroundResource方法后
// 会遗忘padding所以需要重新调用一下
setPadding(left, top, right, bottom);
}
}
private void createImageView() {
imageView = new ImageView(context);
int width = getWidth();
int height = getHeight() / 2;
LayoutParams lp = new LayoutParams(height, height);
imageView.setLayoutParams(lp);
lp.topMargin = height / 2;
lp.leftMargin = (int) (width - height * 1.5f - getPaddingLeft());
if (null != delResId) {
imageView.setImageResource(delResId);
} else if (null != delBitmap) {
imageView.setImageBitmap(delBitmap);
} else {
imageView.setImageResource(R.drawable.custom_control_del);
}
addView(imageView);
imageView.setOnClickListener(this);
if (TextUtils.isEmpty(editText.getText().toString())) {
if (imageView.isShown()) {
imageView.setVisibility(GONE);
}
} else {
if (!imageView.isShown()) {
imageView.setVisibility(VISIBLE);
}
}
}
private Runnable updateImageView = new Runnable() {
@Override
public void run() {
if (getHeight() <= 0) {
new Handler().postDelayed(updateImageView, 100);
} else {
createImageView();
}
}
};
@Override
public void onClick(View v) {
if (v == imageView) {
editText.setText("");
}
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (null == imageView) {
new Handler().postDelayed(updateImageView, 0);
}
if (TextUtils.isEmpty(s.toString())) {
if (null != imageView) {
if (imageView.isShown()) {
imageView.setVisibility(GONE);
}
}
} else {
if (null != imageView) {
if (!imageView.isShown()) {
imageView.setVisibility(VISIBLE);
}
}
}
}
public EditText getEditText() throws RuntimeException {
if (null == editText)
throw new RuntimeException("The input box hasn't been created yet .");
return editText;
}
/**
* 为删除按钮设置本地图片资源的方法
*
* @param resId 资源ID
*/
public void setDelImageResource(int resId) {
//如果没有创建删除按钮,则把资源ID赋值给全局
//如果创建了删除按钮,则当场更改删除图片资源
if (null == imageView) {
delResId = resId;
} else {
imageView.setImageResource(resId);
}
}
/**
* 为删除按钮设置静态位图的方法
*
* @param bm 图片位图
*/
public void setDelImageBitmap(Bitmap bm) {
if (null == imageView) {
delBitmap = bm;
} else {
imageView.setImageBitmap(bm);
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void afterTextChanged(Editable s) {
}
}
简单说一说,这里为什要用 “updateImageView ”线程来完成对 ImageView 的创建及其定位,因为我在调用 “getEditText().setText(“123456”);”为 EditText 赋值时,可能这个自定义组合控件还未初始化完成,getWidth 得到的值会为0,建立的删除按钮就会不可见。那么为什么不在创建 EditText 的时候创建呢?我本着不浪费资源的原则,就要在我需要的时候才创建。所以在这里我就是用 异步线程。
4、demo资源
开源地址:
5、请大家多多指教,贵在分享,思想上的碰撞才能更璀璨!
有问题?我们探讨一下!