andorid之一个标题栏

嗯,这个标题栏,可以说是我在这个项目中学习到的最大的东西。他告诉我一个道理:技术这个东西,越小越精致。

要达到的效果:每个项目都有一个标题头,将这个表头做成一个样式来疯狂复用。

遗憾的是,我只做到了初步的了解,但是如何适应整个屏幕我还是没有做到,看来生命不休学习不能止!


严谨的代码就要有严谨的过程,事情果然是要一步一步做的。


1 首先,要创建一个咩有标题栏的项目:

   重写applicaiton, 

import android.app.Activity;
import android.content.res.Resources;

import com.yanzhenjie.nohttp.Logger;
import com.yanzhenjie.nohttp.NoHttp;

import java.util.ArrayList;

/**
 * Created by SensYang on 2017/05/23 10:16
 */

public class MZApplication extends MultiDexApplication {

    private static MZApplication instance;
    private ArrayList activityList = new ArrayList<>();

    @Override
    public void onCreate() {
        super.onCreate();
        NoHttp.initialize(this);
        Logger.setDebug(true); // 开启NoHttp调试模式。
        Logger.setTag("Omi_NoHttp--->"); // 设置NoHttp打印Log的TAG。
    }

    public static MZApplication getInstance(){
        return instance;
    }
    private Resources resources;

    @Override
    public Resources getResources() {
        if (resources == null) resources = super.getResources();
        return resources;
    }
    /**
     * 记录一条Activity信息
     */
    public void addActivity(Activity activity) {
        if (!activityList.equals(activity)) {
            activityList.add(activity);
        }
    }
    /**
     * 删除一条Activity的信息
     */
    public void removeActivity(Activity activity) {
        activityList.remove(activity);
    }
    @Override
    public void onTerminate() {
        clearActivitys();
        super.onTerminate();
        System.exit(0);
    }

    /**
     * 清空所有activity
     */
    public void clearActivitys() {
        for (Activity activity : activityList) {
            activity.finish();
        }
        activityList.clear();
    }
}
父类:

import android.app.Application;
import android.content.Context;
import android.support.multidex.MultiDex;

public class MultiDexApplication extends Application {
    public MultiDexApplication() {
    }

    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        MultiDex.install(this);//需要在清单文件中添加引用声明:compile 'com.android.support:multidex:+'

    }
}


  在清单文件中,声明使用这个重写的applicaiton。

    android:name=".MZApplication"
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/LauncherTheme"
    >

所有,这个theme的style也需要自己去写了,这里刚好有每个界面的开启关闭动画。

在资源文件中的style下




     看到这里就知道,每个界面的开启动画关闭动画都在这里直接设置:

xml version="1.0" encoding="utf-8"?>
xmlns:android="http://schemas.android.com/apk/res/android"
           android:duration="300"
           android:fromXDelta="100%p"
           android:toXDelta="0" />

xml version="1.0" encoding="utf-8"?>
xmlns:android="http://schemas.android.com/apk/res/android"
           android:duration="300"
           android:fromXDelta="0"
           android:toXDelta="-25%p" />

xml version="1.0" encoding="utf-8"?>
xmlns:android="http://schemas.android.com/apk/res/android"
           android:duration="300"
           android:fromXDelta="-25%p"
           android:toXDelta="0" />


xml version="1.0" encoding="utf-8"?>
xmlns:android="http://schemas.android.com/apk/res/android"
           android:duration="300"
           android:fromXDelta="0.0"
           android:toXDelta="100.0%p" />

至此,第一步结束:得到了一个没有标题栏的项目,下一步:创建一个标题栏!


2 创建标题栏

     2.1 标题栏的databinding布局:

xml version="1.0" encoding="utf-8"?>
xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools">

    

                    name="isShowNewDot"
            type="Boolean"/>
    

            android:layout_width="match_parent"
        android:layout_height="50dp">

                    android:id="@+id/leftRL"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:minWidth="33dp"
            android:paddingLeft="15dp">

                            android:id="@+id/leftIV"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_marginBottom="15dp"
                android:layout_marginTop="15dp"
                android:adjustViewBounds="true"
                android:paddingRight="3.5dp"
                tools:ignore="ContentDescription"/>

                            android:id="@+id/leftNewDot"
                android:layout_width="7dp"
                android:layout_height="7dp"
                android:layout_alignRight="@id/leftIV"
                android:layout_alignTop="@id/leftIV"
                android:layout_marginTop="-3.5dp"
                android:visibility="gone"/>

                            android:id="@+id/leftTV"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_toRightOf="@id/leftIV"
                android:gravity="right|center_vertical"
                android:lines="1"
                android:textColor="@color/white"
                android:textSize="16sp"/>
        

                    android:id="@+id/centerTV"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_centerInParent="true"
            android:ellipsize="marquee"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:gravity="center"
            android:marqueeRepeatLimit="marquee_forever"
            android:maxLines="1"
            android:scrollHorizontally="true"
            android:textColor="@color/white"
            android:textSize="19sp"/>

                    android:id="@+id/topBarRightSecond"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_marginBottom="15dp"
            android:layout_marginTop="15dp"
            android:layout_toLeftOf="@+id/rightLL"
            android:visibility="gone"
            tools:ignore="ContentDescription"/>

                    android:id="@+id/rightLL"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_alignParentRight="true"
            android:minWidth="33dp"
            android:orientation="horizontal"
            android:paddingRight="15dp">

                            android:id="@+id/rightTV"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:background="@null"
                android:gravity="right|center_vertical"
                android:lines="1"
                android:textColor="@color/white"
                android:textSize="16sp"/>

                            android:id="@+id/rightIV"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_marginBottom="15dp"
                android:layout_marginTop="15dp"
                android:adjustViewBounds="true"
                tools:ignore="ContentDescription"/>
        
    

   2.2  标题栏的代码:

         有两个特别的地方

import android.content.Context;
import android.content.res.TypedArray;
import android.databinding.DataBindingUtil;
import android.os.Build;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;

import itcast.zz.kdniaodemo.databinding.WidgetTopNavigationBarBinding;


/**
 * Created by SensYang on 2016/6/3.
 */
public class TopNavigationBar extends FrameLayout {
    private boolean hasSetStatusBarHeight = false;
    private float alpha = 1;
    private int color;
    private WidgetTopNavigationBarBinding navigationBarBinding;

    public TopNavigationBar(Context context) {
        this(context, null);
    }

    public TopNavigationBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        color = Config.getMain_color();
        if (color != -1) setBackgroundColor(color);
        else setBackgroundResource(R.color.main_color);
        navigationBarBinding = DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.widget_top_navigation_bar, this, true);
        // 初始化属性
        this.initializeAttributes(context, attrs);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (!hasSetStatusBarHeight) {
            hasSetStatusBarHeight = true;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                int left = getPaddingLeft();
                int top = getPaddingTop() + DisplayUtil.getStatusBarHeight();//这里,是确定标题栏距离顶部距离的地方
                int right = getPaddingRight();
                int bottom = getPaddingBottom();
                setPadding(left, top, right, bottom);
                getLayoutParams().height = LayoutParams.WRAP_CONTENT;
            }
            setBackgroundAlpha(alpha);
        }
    }

    public void setBackgroundAlpha(float alpha) {
        this.alpha = alpha;
        if (getBackground() != null) {
            getBackground().setAlpha((int) (alpha * 255));
        }
    }

    //DeclareOnClickListener 是重写的一个onClick事件,下面有介绍!
    public void setLeftClick(String methodName) {
        if (methodName != null) {   //所以这里也是一个重点
            navigationBarBinding.leftRL.setOnClickListener(new DeclaredOnClickListener(navigationBarBinding.leftRL, methodName));
        }
    }

    public void setRightClick(String methodName) {
        if (methodName != null) {
            navigationBarBinding.rightLL.setOnClickListener(new DeclaredOnClickListener(navigationBarBinding.rightLL, methodName));
        }
    }

    public void setLeftClick(OnClickListener listener) {
        navigationBarBinding.leftRL.setOnClickListener(listener);
    }

    public void setRightClick(OnClickListener listener) {
        navigationBarBinding.rightLL.setOnClickListener(listener);
    }

    public int calculateHeight() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
            return getResources().getDimensionPixelOffset(R.dimen.topbar_height) + DisplayUtil.getStatusBarHeight();
        else return getResources().getDimensionPixelOffset(R.dimen.topbar_height);
    }

    private void initializeAttributes(Context context, AttributeSet attrs) {
        if (attrs == null) return;
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.OmiTheme);
        boolean visibility;
        int resourceId;
        resourceId = typedArray.getResourceId(R.styleable.OmiTheme_backGround, -1);
        if (resourceId != -1) {
            this.setBackgroundResource(resourceId);
        }
        navigationBarBinding.leftTV.setText(typedArray.getText(R.styleable.OmiTheme_leftText));
        visibility = typedArray.getBoolean(R.styleable.OmiTheme_leftVisible, true);
        if (!visibility) {
            navigationBarBinding.leftIV.setVisibility(View.GONE);
        }
        resourceId = typedArray.getResourceId(R.styleable.OmiTheme_leftSrc, -1);
        if (resourceId != -1) {
            navigationBarBinding.leftIV.setImageResource(resourceId);
        }

        navigationBarBinding.centerTV.setText(typedArray.getText(R.styleable.OmiTheme_centerText));

        visibility = typedArray.getBoolean(R.styleable.OmiTheme_rightVisible, true);
        resourceId = typedArray.getResourceId(R.styleable.OmiTheme_rightSrc, -1);
        navigationBarBinding.rightTV.setText(typedArray.getText(R.styleable.OmiTheme_rightText));
        if (!visibility) {
            navigationBarBinding.rightIV.setVisibility(View.GONE);
            navigationBarBinding.topBarRightSecond.setVisibility(View.GONE);
        }
        if (resourceId != -1) {
            navigationBarBinding.rightIV.setImageResource(resourceId);
        }
        resourceId = typedArray.getResourceId(R.styleable.OmiTheme_rightSecondSrc, -1);
        if (resourceId != -1) {
            navigationBarBinding.topBarRightSecond.setVisibility(View.VISIBLE);
            navigationBarBinding.topBarRightSecond.setImageResource(resourceId);
        }
        typedArray.recycle();
    }

    public TextView getLeftTV() {
        return navigationBarBinding.leftTV;
    }

    public ImageView getLeftIV() {
        return navigationBarBinding.leftIV;
    }

    public TextView getCenterTV() {
        return navigationBarBinding.centerTV;
    }

    public TextView getRightTV() {
        return navigationBarBinding.rightTV;
    }

    public ImageView getRightIV() {
        return navigationBarBinding.rightIV;
    }

    /**
     * 设置左边新消息显示状态
     */
    public void setLeftDotVisibility(boolean isVisibility) {
        navigationBarBinding.leftNewDot.setVisibility(isVisibility ? VISIBLE : GONE);
    }

    public void setLeftText(int textRes) {
        if (navigationBarBinding.leftTV != null) navigationBarBinding.leftTV.setText(textRes);
    }

    public void setLeftText(CharSequence text) {
        if (navigationBarBinding.leftTV != null) navigationBarBinding.leftTV.setText(text);
    }

    public void setCenterText(int textRes) {
        if (navigationBarBinding.centerTV != null) navigationBarBinding.centerTV.setText(textRes);
    }

    public void setCenterText(CharSequence text) {
        if (navigationBarBinding.centerTV != null) navigationBarBinding.centerTV.setText(text);
    }

    public void setRightText(int textRes) {
        if (navigationBarBinding.rightTV != null) navigationBarBinding.rightTV.setText(textRes);
    }

    public void setRightText(CharSequence text) {
        if (navigationBarBinding.rightTV != null) navigationBarBinding.rightTV.setText(text);
    }

    public void setRightImageResource(int resId) {
        if (navigationBarBinding.rightIV != null) {
            navigationBarBinding.rightIV.setImageResource(resId);
        }
    }
    public void setTopBound(){
        this.setBackgroundResource(R.color.BEBEBE);
    }
}

2.2.1  如何获取标题栏到顶部的距离,上面用到的

DisplayUtil

import android.content.Context;
import android.content.res.Resources;
import android.util.DisplayMetrics;
import android.view.WindowManager;

import java.lang.reflect.Field;

public class DisplayUtil {

    private static DisplayMetrics displaysMetrics = null;
    private static float scale = -1.0f;

    public static DisplayMetrics getDisplayMetrics() {
        if (null == displaysMetrics) {
            displaysMetrics = new DisplayMetrics();
            WindowManager wm = (WindowManager) MZApplication.getInstance().getSystemService(Context.WINDOW_SERVICE);
            wm.getDefaultDisplay().getMetrics(displaysMetrics);
        }
        return displaysMetrics;
    }

    /**
     * 获取屏幕高度
     */
    public static int getHeight() {
        if (null == displaysMetrics) {
            getDisplayMetrics();
        }
        return displaysMetrics.heightPixels;
    }

    private static int getStatusBarHeight(Resources resources) {
        Class c;
        Object obj;
        Field field;
        int x, sbar = 0;
        try {
            c = Class.forName("com.android.internal.R$dimen");
            obj = c.newInstance();
            field = c.getField("status_bar_height");
            x = Integer.parseInt(field.get(obj).toString());
            sbar = resources.getDimensionPixelSize(x);
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        return sbar;
    }

    private static int statusBarHeight = 0;

    /**
     * 获取状态栏高度
     */
    public static int getStatusBarHeight() {
        if (statusBarHeight == 0 && MZApplication.getInstance() != null) {
            statusBarHeight = getStatusBarHeight(MZApplication.getInstance().getResources());
        }
        return statusBarHeight;
    }

    /**
     * 获取屏幕宽度
     */
    public static int getWidth() {
        if (null == displaysMetrics) {
            getDisplayMetrics();
        }
        return displaysMetrics.widthPixels;
    }

    /**
     * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
     */
    public static float dip2px(float dpValue) {
        if (scale < 0) {
            if (null == displaysMetrics) {
                getDisplayMetrics();
            }
            scale = displaysMetrics.density;
        }
        return dpValue * scale + 0.5f;
    }

    /**
     * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
     */
    public static float px2dip(float pxValue) {
        if (scale < 0) {
            if (null == displaysMetrics) {
                getDisplayMetrics();
            }
            scale = displaysMetrics.density;
        }
        return pxValue / scale + 0.5f;
    }

    /**
     * 根据手机的分辨率从sp 的单位 转成为 dp
     */
    public static float sp2px(float spValue) {
        if (null == displaysMetrics) {
            getDisplayMetrics();
        }
        float fontScale = displaysMetrics.scaledDensity;
        return spValue * fontScale + 0.5f;
    }
}
 

2.2.2 上边用到的重写的点击事件:

import android.content.Context;
import android.content.ContextWrapper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.View;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * Created by SensYang on 2017/05/23 11:18
 */

public class DeclaredOnClickListener implements View.OnClickListener {
    private final View mHostView;
    private final String mMethodName;

    private Method mResolvedMethod;
    private Context mResolvedContext;

    public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) {
        mHostView = hostView;
        mMethodName = methodName;
    }

    @Override
    public void onClick(@NonNull View v) {
        if (mResolvedMethod == null) {
            resolveMethod(mHostView.getContext(), mMethodName);
        }

        try {
            mResolvedMethod.invoke(mResolvedContext, v);
        } catch (IllegalAccessException e) {
            throw new IllegalStateException(
                    "Could not execute non-public method for android:onClick", e);
        } catch (InvocationTargetException e) {
            throw new IllegalStateException(
                    "Could not execute method for android:onClick", e);
        }
    }

    @NonNull
    private void resolveMethod(@Nullable Context context, @NonNull String name) {
        while (context != null) {
            try {
                if (!context.isRestricted()) {
                    final Method method = context.getClass().getMethod(mMethodName, View.class);
                    if (method != null) {
                        mResolvedMethod = method;
                        mResolvedContext = context;
                        return;
                    }
                }
            } catch (NoSuchMethodException e) {
                // Failed to find method, keep searching up the hierarchy.
            }

            if (context instanceof ContextWrapper) {
                context = ((ContextWrapper) context).getBaseContext();
            } else {
                // Can't search up the hierarchy, null out and fail.
                context = null;
            }
        }

        final int id = mHostView.getId();
        final String idText = id == View.NO_ID ? "" : " with id '"
                + mHostView.getContext().getResources().getResourceEntryName(id) + "'";
        throw new IllegalStateException("Could not find method " + mMethodName
                + "(View) in a parent or ancestor Context for android:onClick "
                + "attribute defined on view " + mHostView.getClass() + idText);
    }
}
这个类中,可以根据传递进去的方法的名字进行判断,如果类中有这个方法就直接使用。

在使用的时候需要用到一些命名规范,这是使用之前的最后一步:

values 下创建文件夹:attrs:

xml version="1.0" encoding="utf-8"?>

    name="OmiTheme">
        name="slideAble" format="boolean"/>
        name="backGround" format="reference|color"/>

        name="leftText" format="reference|string"/>
        name="leftVisible" format="boolean"/>
        name="leftSrc" format="reference"/>

        name="centerText" format="reference|string"/>

        name="rightText" format="reference|string"/>
        name="rightVisible" format="boolean"/>
        name="rightSrc" format="reference"/>
        name="rightSecondSrc" format="reference"/>

        name="textSize" format="dimension"/>
        name="textColor" format="color"/>
        name="selectTextColor" format="color"/>
    

    name="CircleImageView">
        name="border_width" format="dimension"/>
        name="border_color" format="color"/>
    

使用这个标题栏:

    android:id="@+id/topNavigationBar"
    style="@style/TopBarStyle"
    omi:centerText="@string/dynamic"
    omi:leftClick="@{@string/top_left_click}"
    omi:leftSrc="@mipmap/back_btn"
    omi:rightClick="@{@string/top_right_click}"
    omi:rightSrc="@mipmap/dynamic_edit"/>

实际使用:

xml version="1.0" encoding="utf-8"?>
xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:omi="http://schemas.android.com/apk/res-auto"
    >

            android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        >

                    android:id="@+id/topNavigationBar"
            style="@style/TopBarStyle"
            omi:centerText="主页面"
            omi:leftSrc="@mipmap/back_btn"
            omi:leftClick="@{@string/top_left_click}"
            />
    




是的,就是这个小小的标题栏,给他设置一个宽高,就可以了:


在使用的那个界面中重写两个方法如果有必要的话:

  omi:leftClick="@{@string/top_left_click}"
这句的左右就是,top_left_click这句string是什么,标题栏就会去引用他的这个界面去找有没有方法名字叫top_left_click的,如果有,就直接给左侧的图片自动加上点击事件,比如 finish();

public void topLeftClick(View view) {
    finish();
}





你可能感兴趣的:(日记)