**丨**版权说明 : 《分享一个可动态变化,多屏适配的ActionBar控件–SuperActionBar》于当前CSDN博客和乘月网属同一原创,转载请说明出处,谢谢。
这个控件一直在项目中使用,Android自带的ActionBar不太好用,且扩展性也不如咱自己实现的ActionBar。SuperActionBar实现了文本和图片标题的动态切换,满足了一些需要灵活调整标题的需求。当然,还有一个特性–自动适配不同屏幕的设备,其原理参考了一些牛人的适配方案。本文纯属分享性文章,仅作些简单的讲解,代码注释以及使用方法的代码示例,希望SuperActionBar能有幸在大家的项目发挥作用或提供实现思路上的帮助。
预览效果图
组织结构
下面按照组织结构顺序贴上代码
1.attr属性,attrs.xml
配置一些标题栏的字体大小,颜色,图标以及参考分辨率标准等等属性
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SuperActionBar">
<attr name="reference_dimension" format="dimension" />
<attr name="img_padding" format="dimension" />
<attr name="text_padding" format="dimension" />
<attr name="img_size" format="dimension" />
<attr name="text_color" format="reference|color" />
<attr name="text_size" format="dimension" />
<attr name="center_text_size" format="dimension" />
<attr name="left_text" format="string" />
<attr name="center_text" format="string" />
<attr name="right_text" format="string" />
<attr name="left_img" format="reference" />
<attr name="center_img" format="reference" />
<attr name="right_img" format="reference" />
</declare-styleable>
</resources>
2.id标识,ids.xml
给view添加tag标识,以便识别身份(如:id_actionbar_location,验证是否为子标题view,且判断其所处ActionBar位置)以及验证是否缩放过,避免重复缩放(如:is_scale_size_tag,验证是否为已经缩放的view),具体请看UI逻辑代码
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="id_actionbar_location" type="id"/>
<item name="is_scale_size_tag" type="id" />
<item name="is_scale_font_tag" type="id" />
</resources>
3.UI逻辑代码,SuperActionBar.java
UI设计逻辑全部于此编写,概括为标题栏元素的生成,排版和缩放
package cn.icheny.super_actionbar;
import android.content.Context;
import android.content.res.TypedArray;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import cn.icheny.super_actionbar;
import static android.widget.ImageView.ScaleType.CENTER_CROP;
import static cn.icheny.super_actionbar.SuperActionBar.Location.CENTER;
import static cn.icheny.super_actionbar.SuperActionBar.Location.LETF;
import static cn.icheny.super_actionbar.SuperActionBar.Location.RIGHT;
/**
* 自定义ActionBar
* 为了统一缩放以适配屏幕,所有尺寸配置请均采用px值表示
*
* @author www.icheny.cn
* @date 2017/12/01.
*/
public class SuperActionBar extends RelativeLayout {
private float scale = 1f;//缩放值
private float text_size;//文字大小
private float center_text_size;//中间文字大小
private int text_color;//文字颜色
private int img_size;//图片标题打下,正方形尺寸
private int img_padding;//图片padding
private int text_padding;//文字padding
private String left_text;//左边文本标题
private String center_text;//中间文本标题
private String right_text;//右边文本标题
private int left_img;//左边图片标题资源
private int center_img;//中间图片标题资源
private int right_img;//右边图片标题资源
private boolean isScaled;//是否已缩放过,这里指的是SuperActionBar
private static final String tag_actionbar_left = "tag_actionbar_left";//左边标题标识
private static final String tag_actionbar_cener = "tag_actionbar_cener";//中间标题标识
private static final String tag_actionbar_right = "tag_actionbar_right";//右边标题标识
public SuperActionBar(Context context) {
this(context, null);
}
public SuperActionBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SuperActionBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initAttributes(attrs);
if (getBackground() == null) {//没有设置背景色,默认设置为主题颜色
TypedValue t = new TypedValue();
getContext().getTheme().resolveAttribute(R.attr.colorPrimary, t, true);
setBackgroundColor(t.data);
}
initBarChilds();
}
private void initAttributes(AttributeSet attrs) {
if (null == attrs) {
return;
}
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.SuperActionBar);
//参考尺寸(以屏幕宽度为标准)
float reference_dimension = a.getDimensionPixelOffset(R.styleable.SuperActionBar_reference_dimension, 1080);
scale = (float) getContext().getResources().getDisplayMetrics().widthPixels * 1f / reference_dimension;
text_size = a.getDimension(R.styleable.SuperActionBar_text_size, 0);
center_text_size = a.getDimension(R.styleable.SuperActionBar_center_text_size, 0);
img_size = a.getDimensionPixelOffset(R.styleable.SuperActionBar_img_size, 0);
img_padding = a.getDimensionPixelOffset(R.styleable.SuperActionBar_img_padding, 0);
text_padding = a.getDimensionPixelOffset(R.styleable.SuperActionBar_text_padding, 0);
text_color = a.getColor(R.styleable.SuperActionBar_text_color, 0);
left_text = a.getString(R.styleable.SuperActionBar_left_text);
center_text = a.getString(R.styleable.SuperActionBar_center_text);
right_text = a.getString(R.styleable.SuperActionBar_right_text);
left_img = a.getResourceId(R.styleable.SuperActionBar_left_img, 0);
center_img = a.getResourceId(R.styleable.SuperActionBar_center_img, 0);
right_img = a.getResourceId(R.styleable.SuperActionBar_right_img, 0);
a.recycle();
}
/**
* 初始化XML配置的标题
*/
private void initBarChilds() {
if (left_text != null)
this.setBarText(left_text, text_size, text_color, LETF);
if (center_text != null)
this.setBarText(center_text, center_text_size > 0 ? center_text_size : text_size, text_color, CENTER);
if (right_text != null)
this.setBarText(right_text, text_size, text_color, RIGHT);
if (left_img != 0)
this.setBarImg(left_img, LETF);
if (center_img != 0)
this.setBarImg(center_img, CENTER);
if (right_img != 0)
this.setBarImg(right_img, RIGHT);
}
private TextView setBarText(CharSequence text, float size, int colorId, Location location) {
View view = checkdBarChild(location);
TextView tv = null;
if (null == view) {
tv = createText(text, size, colorId);
bindBarChild(tv, location);
} else if (view instanceof TextView) {
tv = (TextView) view;
tv.setText(text);
if (colorId != 0) tv.setTextColor(colorId);
if (size > 0) tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, scaleValue((int) size));
} else {
removeView(view);
tv = createText(text, size, colorId);
bindBarChild(tv, location);
}
return tv;
}
private ImageView setBarImg(final String imgName, Location location) {
final int drawableId = getContext().getResources().getIdentifier(imgName, "drawable", getContext().getPackageName());
ImageView iv = setBarImg(drawableId, location);
if (imgName.endsWith("_nor")) {
final ImageView finalIv = iv;
iv.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
//统一处理图片按钮按压效果
touchHandler(finalIv, imgName, drawableId, event);
return false;
}
});
}
return iv;
}
public ImageView setBarImg(int drawableId, Location location) {
//checkdBarChild主要是为了view的复用
View view = checkdBarChild(location);
ImageView iv = null;
if (null == view) {
iv = createImg(drawableId);
bindBarChild(iv, location);
} else if (view instanceof ImageView) {
iv = (ImageView) view;
iv.setImageResource(drawableId);
} else {
removeView(view);
iv = createImg(drawableId);
bindBarChild(iv, location);
}
return iv;
}
/**
* 统一处理图片按钮按压效果,针对传入的资源文件名而不是资源id
*/
private void touchHandler(ImageView iv, String srcName, int drawableId, MotionEvent motionEvent) {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN://按压
String paramPre = srcName.replaceAll("_nor", "_pre");
int drawableIdPre = getResources().getIdentifier(paramPre, "drawable", getContext().getPackageName());
iv.setImageResource(drawableIdPre);
break;
case MotionEvent.ACTION_UP://释放
//这里不做上面的获取资源id操作,直接用原id,是为了节省运行资源
iv.setImageResource(drawableId);
break;
}
}
private View checkdBarChild(Location location) {
for (int i = 0, count = getChildCount(); i < count; i++) {
View child = getChildAt(i);
Object tag = child.getTag(R.id.id_actionbar_location);
if (tag_actionbar_left.equals(tag) && LETF.equals(location)) {//已存在左边标题,移除该标题的view对象,以便新标题view代替它,以下同理
return child;
}
if (tag_actionbar_cener.equals((tag)) && CENTER.equals(location)) {
return child;
}
if (tag_actionbar_right.equals((tag)) && RIGHT.equals(location)) {
return child;
}
}
return null;
}
private void bindBarChild(View view, final Location location) {
view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
switch (location) {
case LETF:
if (mClickListner != null) mClickListner.onLeftClick(v);
break;
case CENTER:
if (mClickListner != null) mClickListner.onCenterClick(v);
break;
case RIGHT:
if (mClickListner != null) mClickListner.onRightClick(v);
break;
}
}
});
RelativeLayout.LayoutParams lp = (LayoutParams) view.getLayoutParams();
switch (location) {
case LETF:
lp.addRule(ALIGN_PARENT_LEFT);
lp.addRule(CENTER_VERTICAL);
view.setTag(R.id.id_actionbar_location, tag_actionbar_left);
break;
case CENTER:
lp.addRule(CENTER_IN_PARENT);
view.setTag(R.id.id_actionbar_location, tag_actionbar_cener);
break;
case RIGHT:
lp.addRule(CENTER_VERTICAL);
lp.addRule(ALIGN_PARENT_RIGHT);
view.setTag(R.id.id_actionbar_location, tag_actionbar_right);
break;
}
view.setLayoutParams(lp);
scaleView(view);
}
private TextView createText(CharSequence text, float size, int colorId) {
TextView tv = new TextView(getContext());
tv.setText(text);
tv.setMaxLines(1);
tv.setEllipsize(TextUtils.TruncateAt.END);
if (colorId != 0) tv.setTextColor(colorId);
if (size > 0) tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
addView(tv);
LayoutParams lp = (LayoutParams) tv.getLayoutParams();
lp.width = LayoutParams.WRAP_CONTENT;
lp.height = LayoutParams.WRAP_CONTENT;
tv.setPadding(text_padding, text_padding, text_padding, text_padding);
tv.setLayoutParams(lp);
return tv;
}
private ImageView createImg(int drawableId) {
ImageView iv = new ImageView(getContext());
iv.setImageResource(drawableId);
iv.setScaleType(CENTER_CROP);
addView(iv);
LayoutParams lp = (LayoutParams) iv.getLayoutParams();
lp.width = img_size == 0 ? LayoutParams.WRAP_CONTENT : img_size;
lp.height = img_size == 0 ? LayoutParams.WRAP_CONTENT : img_size;
iv.setPadding(img_padding, img_padding, img_padding, img_padding);
iv.setLayoutParams(lp);
return iv;
}
/**
* 对view进行缩放
*
* @param view
*/
private void scaleView(View view) {
scaleViewSize(view);
if (view instanceof ViewGroup) {
ViewGroup group = (ViewGroup) view;
for (int i = 0, size = group.getChildCount(); i < size; i++) {
scaleView(group.getChildAt(i));
}
}
if (view instanceof TextView) {
scaleTextView((TextView) view);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
/**
* 针对SuperActionBar本身的缩放,为什么不放在构造方法或者attachToWindow()等函数里作缩放?
* 因为这些函数执行时SuperActionBar还没有被加入父View(mParent),
* 此时该view的mLayoutParams为null,那就不可能对该view的mLayoutParams进行缩放了
*/
if (!isScaled) {
scaleViewSize(this);
isScaled = true;
}
}
/**
* 缩放view小大
*
* @param view
*/
private void scaleViewSize(View view) {
Object tag = view.getTag(R.id.is_scale_size_tag);
//判断是否已经被缩放过,是则直接return掉,否则添加缩放标记并行缩放操作
if (tag instanceof Boolean && (boolean) tag) return;
view.setTag(R.id.is_scale_size_tag, true);
int paddingLeft = scaleValue(view.getPaddingLeft());
int paddingTop = scaleValue(view.getPaddingTop());
int paddingRight = scaleValue(view.getPaddingRight());
int paddingBottom = scaleValue(view.getPaddingBottom());
view.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
ViewGroup.LayoutParams lp = view.getLayoutParams();
if (lp == null) return;
if (lp.width > 0) lp.width = scaleValue(lp.width);
if (lp.height > 0) lp.height = scaleValue(lp.height);
if (lp instanceof MarginLayoutParams) {
MarginLayoutParams mlp = (MarginLayoutParams) lp;
mlp.leftMargin = scaleValue(mlp.leftMargin);
mlp.topMargin = scaleValue(mlp.topMargin);
mlp.rightMargin = scaleValue(mlp.rightMargin);
mlp.bottomMargin = scaleValue(mlp.bottomMargin);
}
view.setLayoutParams(lp);
}
/**
* 缩放TextView文字小大
*
* @param textView
*/
private void scaleTextView(TextView textView) {
Object tag = textView.getTag(R.id.is_scale_font_tag);
//判断文字大小是否已被缩放过,是则直接return掉,否则添加缩放标记并行缩放操作
if (tag instanceof Boolean && (boolean) tag) return;
textView.setTag(R.id.is_scale_font_tag, true);
float size = textView.getTextSize() * scale;
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
}
public int scaleValue(int value) {
return value <= 1 ? value : Math.round(scale * value);
}
//--------------------------左边文本标题-----------------------------
public TextView setBarLeftText(CharSequence text) {
return this.setBarText(text, text_size, text_color, LETF);
}
public TextView setBarLeftText(CharSequence text, float size) {
return this.setBarText(text, size, text_color, LETF);
}
public TextView setBarLeftText(CharSequence text, int colorId) {
return this.setBarText(text, text_size, colorId, LETF);
}
public TextView setBarLeftText(CharSequence text, float size, int colorId) {
return this.setBarText(text, size, colorId, LETF);
}
//--------------------------中间文本标题-----------------------------
public TextView setBarCenterText(CharSequence text) {
return this.setBarText(text, center_text_size > 0 ? center_text_size : text_size, text_color, CENTER);
}
public TextView setTitle(CharSequence text) {
return this.setBarText(text, center_text_size > 0 ? center_text_size : text_size, text_color, CENTER);
}
public TextView setBarCenterText(CharSequence text, float size) {
return this.setBarText(text, size, text_color, CENTER);
}
public TextView setBarCenterText(CharSequence text, int colorId) {
return this.setBarText(text, center_text_size > 0 ? center_text_size : text_size, colorId, CENTER);
}
public TextView setBarCenterText(CharSequence text, float size, int colorId) {
return this.setBarText(text, size, colorId, CENTER);
}
//--------------------------右边文本标题-----------------------------
public TextView setBarRightText(CharSequence text) {
return this.setBarText(text, text_size, text_color, RIGHT);
}
public TextView setBarRightText(CharSequence text, float size) {
return this.setBarText(text, size, text_color, RIGHT);
}
public TextView setBarRightText(CharSequence text, int colorId) {
return this.setBarText(text, text_size, colorId, RIGHT);
}
public TextView setBarRightText(CharSequence text, float size, int colorId) {
return this.setBarText(text, size, colorId, RIGHT);
}
//--------------------------左边图片标题-----------------------------
public ImageView setBarLeftImg(String srcName) {
return this.setBarImg(srcName, LETF);
}
public ImageView setBarLeftImg(int drawableId) {
return this.setBarImg(drawableId, LETF);
}
//--------------------------中间图片标题-----------------------------
public ImageView setBarCenterImg(String srcName) {
return this.setBarImg(srcName, CENTER);
}
public ImageView setBarCenterImg(int drawableId) {
return this.setBarImg(drawableId, CENTER);
}
//--------------------------右边图片标题-----------------------------
public ImageView setBarRightImg(String srcName) {
return this.setBarImg(srcName, RIGHT);
}
public ImageView setBarRightImg(int drawableId) {
return this.setBarImg(drawableId, RIGHT);
}
private OnActionBarClickListner mClickListner;
public void setOnActionBarClickListner(OnActionBarClickListner l) {
mClickListner = l;
}
/**
* 监听接口,顾名思义
*/
public interface OnActionBarClickListner {
void onLeftClick(View v);
void onCenterClick(View v);
void onRightClick(View v);
}
/**
* ActionBar左中右结构
*/
public static enum Location {
LETF, CENTER, RIGHT
}
}
使用示例
这里直接粘贴预览图实现的代码,activity_main.xml,btn_back_selector.xml,MainActivity.java
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="cn.icheny.super_actionbar.MainActivity">
<cn.icheny.super_actionbar.view.SuperActionBar
android:id="@+id/id_action_bar"
android:layout_width="match_parent"
android:layout_height="130px"
android:paddingLeft="15px"
android:paddingRight="15px"
app:center_text="中间标题"
app:center_text_size="70px"
app:img_padding="20px"
app:img_size="120px"
app:reference_dimension="1080px"
app:left_img="@drawable/btn_back_selector"
app:right_text="右边标题"
app:text_color="@color/white"
app:text_padding="15px"
app:text_size="42px" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:onClick="change"
android:textSize="60px"
android:text="动态切换" />
</FrameLayout>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/btn_back_pre" android:state_pressed="true" />
<item android:drawable="@drawable/btn_back_nor" android:state_pressed="false" />
</selector>
package cn.icheny.super_actionbar;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;
import cn.icheny.super_actionbar.view.SuperActionBar;
import java.util.Random;
public class MainActivity extends AppCompatActivity implements SuperActionBar.OnActionBarClickListner {
protected SuperActionBar mActionBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initActionBar();
mActionBar.setOnActionBarClickListner(this);
}
/**
* 初始化ActionBar,使用时需确认当前Activity的布局是否添加了ActionBar控件
*/
protected void initActionBar() {
mActionBar = findViewById(R.id.id_action_bar);
}
@Override
public void onLeftClick(View v) {
showToast("onLeftClick");
}
@Override
public void onCenterClick(View v) {
showToast("onCenterClick");
}
@Override
public void onRightClick(View v) {
showToast("onRightClick");
}
public void change(View view) {
Random random = new Random();
int left = random.nextInt(2);
if (0 == left) {
mActionBar.setBarLeftText("左边标题");
} else {
mActionBar.setBarLeftImg(R.drawable.btn_back_selector);
}
int center = random.nextInt(2);
if (0 == center) {
mActionBar.setBarCenterText("中间标题", 70f);
} else {
mActionBar.setBarCenterImg(R.mipmap.ic_launcher);
}
int right = random.nextInt(2);
if (0 == right) {
mActionBar.setBarRightText("右边标题");
} else {
mActionBar.setBarRightImg(R.mipmap.ic_launcher_round);
}
}
private void showToast(CharSequence msg){
Toast.makeText(MainActivity.this,msg,Toast.LENGTH_SHORT).show();
}
}
建议将Activity的 mActionBar 属性和initActionBar()方法写到封装的BaseActivity中,以便直接使用。
好了,以上为本文的全部内容,又水了一篇。欢迎留言,给出自己的建议,谢谢!文章会不定期更新~