在开发的时候,经常会用到这样一个控件:上面是图片,下面是文字,有同学就问了,TextView本身不就可以同时显示图片和文字吗?但是,公司的需求往往不是那么简单,比如:按下的时候,图片要发生改变,文字颜色要发生改变,整个控件的背景颜色也要相应加深。这个时候,如果定义一大堆的监听事件,会让代码凌乱,而且效率低下,是时候自定义一个控件了。
- 定义styleable,文件名为attrs.xml,放在values文件夹下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ImageText">
<attr name="width" format="dimension" />
<attr name="height" format="dimension" />
<attr name="image_width" format="dimension" />
<attr name="image_height" format="dimension" />
<attr name="image_normal" format="reference|color" />
<attr name="image_pressed" format="reference|color" />
<attr name="padding_top" format="dimension" />
<attr name="padding_right" format="dimension" />
<attr name="padding_bottom" format="dimension" />
<attr name="padding_left" format="dimension" />
<attr name="bg_normal_color" format="reference|color" />
<attr name="bg_pressed_color" format="reference|color" />
<attr name="text_margin_top" format="dimension" />
<attr name="text_normal_color" format="reference|color" />
<attr name="text_pressed_color" format="reference|color" />
<attr name="text_size" format="dimension" />
<attr name="text" format="string" />
</declare-styleable>
</resources>
- 组成控件的UI view_image_text.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_horizontal"
android:id="@+id/ll_frame"
android:descendantFocusability="blocksDescendants">
<View
android:id="@+id/view_space"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:visibility="gone"/>
<ImageView
android:id="@+id/iv_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<View
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"/>
<TextView
android:id="@+id/tv_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="end"
android:gravity="center"/>
</LinearLayout>
- 自定义View:
package com.pax.supercashier.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.pax.supercashier.R;
import com.pax.supercashier.utils.UIUtils;
/**
* 2017-12-25
* @author Jason Zhan
*/
public class ImageText extends LinearLayout {
private LinearLayout ll_frame;
private ImageView iv_image;
private View view_space;
private TextView tv_text;
private int image_normal;
private int image_pressed;
private int bg_normal_color;
private int bg_pressed_color;
private int text_normal_color;
private int text_pressed_color;
public ImageText(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.view_image_text, this);
ll_frame = findViewById(R.id.ll_frame);
iv_image = findViewById(R.id.iv_image);
view_space = findViewById(R.id.view_space);
tv_text = findViewById(R.id.tv_text);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ImageText);
final int width = UIUtils.dip2px(context, typedArray.getDimension(R.styleable.ImageText_width, 0));
final int height = UIUtils.dip2px(context, typedArray.getDimension(R.styleable.ImageText_height, 0));
final int image_width = UIUtils.dip2px(context, typedArray.getDimension(R.styleable.ImageText_image_width, 0));
final int image_height = UIUtils.dip2px(context, typedArray.getDimension(R.styleable.ImageText_image_height, 0));
image_normal = typedArray.getResourceId(R.styleable.ImageText_image_normal, R.mipmap.ic_launcher);
image_pressed = typedArray.getResourceId(R.styleable.ImageText_image_pressed, R.mipmap.ic_launcher);
final int padding_left = UIUtils.dip2px(context, typedArray.getDimension(R.styleable.ImageText_padding_left, 0));
final int padding_top = UIUtils.dip2px(context, typedArray.getDimension(R.styleable.ImageText_padding_top, 0));
final int padding_right = UIUtils.dip2px(context, typedArray.getDimension(R.styleable.ImageText_padding_right, 0));
final int padding_bottom = UIUtils.dip2px(context, typedArray.getDimension(R.styleable.ImageText_padding_bottom, 0));
bg_normal_color = typedArray.getColor(R.styleable.ImageText_bg_normal_color, 0);
bg_pressed_color = typedArray.getColor(R.styleable.ImageText_bg_pressed_color, 0);
final int text_margin_top = UIUtils.dip2px(context, typedArray.getDimension(R.styleable.ImageText_text_margin_top, 0));
text_normal_color = typedArray.getColor(R.styleable.ImageText_text_normal_color, 0);
text_pressed_color = typedArray.getColor(R.styleable.ImageText_text_pressed_color, 0);
final int text_size = UIUtils.sp2px(context, typedArray.getDimension(R.styleable.ImageText_text_size, UIUtils.sp2px(context, 16)));
String text = typedArray.getString(R.styleable.ImageText_text);
typedArray.recycle();
LayoutParams params = new LayoutParams(width, height);
if (width == 0 || height == 0) {
params.width = LayoutParams.MATCH_PARENT;
params.height = LayoutParams.MATCH_PARENT;
}
ll_frame.setLayoutParams(params);
ll_frame.setPadding(padding_left, padding_top, padding_right, padding_bottom);
ll_frame.setBackgroundColor(bg_normal_color);
if (TextUtils.isEmpty(text)) {
tv_text.setVisibility(View.GONE);
view_space.setVisibility(View.VISIBLE);
} else {
tv_text.setVisibility(View.VISIBLE);
view_space.setVisibility(View.GONE);
tv_text.setText(text);
tv_text.setTextSize(text_size);
tv_text.setTextColor(text_normal_color);
}
ViewTreeObserver vto = tv_text.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
tv_text.getViewTreeObserver().removeGlobalOnLayoutListener(this);
if (image_width == 0 || image_height == 0) {
int imageTempHeight = height - padding_top - padding_bottom - text_margin_top - tv_text.getHeight();
int imageTempWidth = width - padding_left - padding_right;
int imageWidth = imageTempWidth < imageTempHeight ? imageTempWidth : imageTempHeight;
iv_image.setLayoutParams(new LayoutParams(imageWidth, imageWidth));
iv_image.setScaleType(ImageView.ScaleType.FIT_XY);
iv_image.setBackgroundResource(image_normal);
} else {
iv_image.setLayoutParams(new LayoutParams(image_width, image_height));
iv_image.setScaleType(ImageView.ScaleType.FIT_XY);
iv_image.setBackgroundResource(image_normal);
}
}
});
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
tv_text.setTextColor(text_pressed_color);
iv_image.setBackgroundResource(image_pressed);
ll_frame.setBackgroundColor(bg_pressed_color);
break;
case MotionEvent.ACTION_UP:
tv_text.setTextColor(text_normal_color);
iv_image.setBackgroundResource(image_normal);
ll_frame.setBackgroundColor(bg_normal_color);
break;
default:
break;
}
return true;
}
}
- 使用:
先在根布局添加
xmlns:it="http://schemas.android.com/apk/res-auto"
再使用:
<com.pax.supercashier.view.ImageText
android:layout_width="match_parent"
android:layout_height="match_parent"
it:image_width="@dimen/size_top_menu_width"
it:image_height="@dimen/size_top_menu_height"
it:bg_normal_color="@color/blue_dark"
it:bg_pressed_color="@color/blue_dark_pressed"
it:padding_top="@dimen/padding_frame"
it:padding_bottom="@dimen/padding_frame"
it:padding_right="0dp"
it:padding_left="0dp"
it:text_margin_top="@dimen/margin_menu_top"
it:text="Staff"
it:text_size="@dimen/text_size_menu"
it:text_normal_color="@color/white"
it:text_pressed_color="@color/white"
it:image_normal="@drawable/staff_normal"
it:image_pressed="@drawable/staff_pressed"
android:layout_centerInParent="true"/>
好了,一个框架就搭起来了,剩下的工作就是默认值的配置,wrap_content的支持,方向的支持,UI适配等。