分享一个可动态变化,多屏适配的ActionBar控件–SuperActionBar

原创 cheny  2017-12-01 21:42  阅读 370 次 评论 0 条
摘要:

这个控件一直在项目中使用,Android自带的ActionBar不太好用,且扩展性也不如咱自己实现的ActionBar。SuperActionBar实现了文本和图片标题的动态切换,满足了一些需要灵活调整标题的需求。当然,还有一个特性–自动适配不同屏幕的设备,其原理参考了一些牛人的适配方案。本文纯属分享性文章,仅作些简单的讲解,代码注释以及使用方法的代码示例,希望SuperActionBar能有幸在大家的项目发挥作用或提供实现思路上的帮助。

版权说明 : 《分享一个可动态变化,多屏适配的ActionBar控件--SuperActionBar》于当前CSDN博客乘月网属同一原创,转载请说明出处,谢谢。

这个控件一直在项目中使用,Android自带的ActionBar不太好用,且扩展性也不如咱自己实现的ActionBar。SuperActionBar实现了文本和图片标题的动态切换,满足了一些需要灵活调整标题的需求。当然,还有一个特性--自动适配不同屏幕的设备,其原理参考了一些牛人的适配方案。本文纯属分享性文章,仅作些简单的讲解,代码注释以及使用方法的代码示例,希望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中,以便直接使用。

 好了,以上为本文的全部内容,又水了一篇。欢迎留言,给出自己的建议,谢谢!文章会不定期更新~

本文地址:https://www.icheny.cn/archives/563
关注公众号“我的IT小地方”:扫二维码乘月网的公众号 or 搜索公众号:it_place
版权声明:本文为原创文章,版权归 cheny 所有,欢迎分享本文,转载请保留出处!

发表评论


表情