第二天.基类搭建

2023-09-11  本文已影响0人  ryanxun
嘿,今天的你过的还好吗

经过上一天的搭建...今天狠狠地搞基类


image.png

这是我最后都完事的情况

首先是baseactivity和basefragment和baseviewmodel和baseapplication/这些基本所有项目都需要用到的.贴不贴没啥用嗷.想要的去代码里copy/值得一提的是我把loading也架在了基类中.为什么呢.因为.你总有不想让别人看到的东西...需要靠加载来掩盖.我还很贴心的搞了个自定义的Toast.不为别的.就喜欢自定义一小下.
loading采用了三方的XPopup
贴点代码吧
首先是BaseActivity

package com.example.basic.activity

import android.graphics.ColorMatrix
import android.graphics.ColorMatrixColorFilter
import android.graphics.Paint
import android.os.Bundle
import android.view.MotionEvent
import android.view.View
import android.view.WindowManager
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import com.example.basic.R
import com.example.basic.adapter.ScreenAutoAdapter
import com.example.basic.view.Loading
import com.lxj.xpopup.util.KeyboardUtils
import com.example.basic.listener.BackPressedListener
import java.util.Calendar
import com.gyf.immersionbar.ImmersionBar

/**
 * Author: lsx
 * Description
 * Date:2023/9/12 13:11
 */
abstract class BaseActivity : AppCompatActivity() {
    abstract fun layoutId(): Int
    abstract fun initView(savedInstanceState: Bundle?)
    override fun onCreate(savedInstanceState: Bundle?) {
        //屏幕适配
        ScreenAutoAdapter.match(this, 360.0f)
        super.onCreate(savedInstanceState)
        afterOnCreate()
        //设置布局
        setLayoutView()
        //view层
        initView(savedInstanceState)
        //沉浸式状态栏
        initImmersionBar()
        val calendar = Calendar.getInstance()
        //纪念江泽民
//        if (calendar.timeInMillis < TimeUtils.string2Millis("2022-12-07 00:00:00")) {
//            setGraySheme(0f)
//        }
    }

    open fun afterOnCreate() {
    }

    open fun setLayoutView() {
        val layoutId = layoutId()
        if (layoutId != 0) {
            setContentView(layoutId)
        }
    }

    protected open fun initImmersionBar() {
        ImmersionBar.with(this).fitsSystemWindows(true) //使用该属性,必须指定状态栏颜色
            .keyboardEnable(keyboardEnable()) //解决软键盘与底部输入框冲突问题
            .keyboardMode(
                WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN or WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
            ).statusBarColor(R.color.base_color_white).navigationBarColor(R.color.base_color_white)
            .navigationBarDarkIcon(true).statusBarDarkFont(
                true, 0.2f
            ) //原理:如果当前设备支持状态栏字体变色,会设置状态栏字体为黑色,如果当前设备不支持状态栏字体变色,会使当前状态栏加上透明度,否则不执行透明度
            .init()
    }

    protected open fun keyboardEnable(): Boolean {
        return false
    }

    fun showLoading() {
        Loading.show(this)
    }

    open fun hideLoading() {
        Loading.dismiss()
    }

    override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
        if (ev.action == MotionEvent.ACTION_DOWN) {
            currentFocus?.let {
                if (isShouldHideKeyboard(it, ev)) {
                    KeyboardUtils.hideSoftInput(it)
                    currentFocus?.clearFocus()
                }
            }
        }
        return super.dispatchTouchEvent(ev)
    }

    // Return whether touch the view.
    private fun isShouldHideKeyboard(v: View, event: MotionEvent): Boolean {
        if ((v is EditText)) {
            val l = intArrayOf(0, 0)
            v.getLocationOnScreen(l)
            val left = l[0]
            val top = l[1]
            val bottom = top + v.getHeight()
            val right = left + v.getWidth()
            return !(event.rawX > left && event.rawX < right && event.rawY > top && event.rawY < bottom)
        }
        return false
    }

    private fun setGraySheme(gray: Float) {
        val decorView = window.decorView
        val paint = Paint()
        val cm = ColorMatrix()
        cm.setSaturation(gray)
        paint.colorFilter = ColorMatrixColorFilter(cm)
        decorView.setLayerType(View.LAYER_TYPE_HARDWARE, paint)
    }

    override fun onBackPressed() {
        if (!interceptBackPressed()) {
            super.onBackPressed()
        }
    }

    private fun interceptBackPressed(): Boolean {
        supportFragmentManager.fragments.forEach {
            if (processAllFragment(it)) {
                return true
            }
        }
        return false
    }

    // 遍历所有fragment
    private fun processAllFragment(
        fragment: Fragment
    ): Boolean {
        for (childFragment in fragment.childFragmentManager.fragments) {
            if (processAllFragment(childFragment)) {
                return true
            }
        }
        if (fragment is BackPressedListener) {
            if (fragment.handleBackPressed()) {
                return true
            }
        }
        return false
    }
}

然后是BaseFragment

package com.example.basic.fragment

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.ColorRes
import androidx.fragment.app.Fragment
import com.example.basic.R
import com.example.basic.view.Loading
import com.gyf.immersionbar.ImmersionBar

abstract class BaseFragment : Fragment() {

    /**
     * 当前Fragment绑定的视图布局
     */
    abstract fun layoutId(): Int

    /**
     * 初始化view
     */
    abstract fun initView(savedInstanceState: Bundle?)

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(layoutId(), container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        afterOnViewCreated()
        initView(savedInstanceState)
    }

    open fun afterOnViewCreated(){
    }
    fun showLoading(){
        activity?.let { Loading.show(it) }
    }
    fun hideLoading(){
        activity?.let { Loading.dismiss() }
    }


    fun initImmersionBar(@ColorRes statusBarColor: Int) {
        ImmersionBar.with(this).fitsSystemWindows(true) //使用该属性,必须指定状态栏颜色
            .keyboardEnable(keyboardEnable()) //解决软键盘与底部输入框冲突问题
            .statusBarColor(statusBarColor)
            .navigationBarColor(R.color.base_color_white).statusBarDarkFont(
                true, 0.2f
            ) //原理:如果当前设备支持状态栏字体变色,会设置状态栏字体为黑色,如果当前设备不支持状态栏字体变色,会使当前状态栏加上透明度,否则不执行透明度
            .init()
    }

    protected open fun keyboardEnable(): Boolean {
        return false
    }

}

当然了 db和vm都适配了...但是那是另外两个了.有想法的可以自行去copy.

搞了个入侵性很低的屏幕适配

package com.example.basic.adapter;

import android.app.Activity;
import android.app.Application;
import android.content.ComponentCallbacks;
import android.content.Context;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.util.DisplayMetrics;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;

/**
 * 应用模块:base
 * <p>
 * 类描述: 屏幕适配 1.先在application中使用setup()方法初始化一下
 * 2.手动在Activity中调用match()方法做适配,必须在setContentView()之前
 * 3.建议使用dp做宽度适配,大多数时候宽度适配才是主流需要 4.个人觉得在写布局的时候,可以多用dp,如果是使用px,建议转化成dp
 * 5.入侵性很低,不需要改动原来的代码
 *
 * <p>
 *
 * @author lsx
 * @since 2020-02-21
 */
public class ScreenAutoAdapter {
    /**
     * 屏幕适配的基准
     */
    private static final int MATCH_BASE_WIDTH = 0;

    private static final int MATCH_BASE_HEIGHT = 1;

    /**
     * 适配单位
     */
    private static final int MATCH_UNIT_DP = 0;

    private static final int MATCH_UNIT_PT = 1;

    /**
     * 适配信息
     */
    private static MatchInfo sMatchInfo;

    /**
     * Activity 生命周期检测
     */
    private static Application.ActivityLifecycleCallbacks mActivityLifecycleCallbacks;

    /**
     * 初始化
     *
     * @param application 需要在application中初始化
     */
    public static void setup(@NonNull final Application application) {

        /*
         * //获取屏幕分辨率信息的三种方法 //第一种 DisplayMetrics metrics = new DisplayMetrics();
         * Display display = activity.getWindowManager().getDefaultDisplay();
         * display.getMetrics(metrics); //第二种 DisplayMetrics metrics=
         * activity.getResources().getDisplayMetrics(); //第三种
         * Resources.getSystem().getDisplayMetrics();
         */

        // 注意这个是获取系统的displayMetrics
        final DisplayMetrics displayMetrics =
                application.getResources().getDisplayMetrics();
        if (sMatchInfo == null) {
            // 记录系统的原始值
            sMatchInfo = new MatchInfo();
            sMatchInfo.setScreenWidth(displayMetrics.widthPixels);
            sMatchInfo.setScreenHeight(displayMetrics.heightPixels);
            sMatchInfo.setAppDensity(displayMetrics.density);
            sMatchInfo.setAppDensityDpi(displayMetrics.densityDpi);
            sMatchInfo.setAppScaledDensity(displayMetrics.scaledDensity);
            sMatchInfo.setAppXdpi(displayMetrics.xdpi);
        }
        // 添加字体变化的监听
        // 调用 Application#registerComponentCallbacks 注册下 onConfigurationChanged
        // 监听即可。
        application.registerComponentCallbacks(new ComponentCallbacks() {
            @Override
            public void onConfigurationChanged(Configuration newConfig) {
                // 字体改变后,将 appScaledDensity 重新赋值
                if (newConfig != null && newConfig.fontScale > 0) {
                    float scaledDensity = displayMetrics.scaledDensity;
                    sMatchInfo.setAppScaledDensity(scaledDensity);
                }
            }

            @Override
            public void onLowMemory() {

            }
        });
    }

    /**
     * 在 application 中全局激活适配(也可单独使用 match() 方法在指定页面中配置适配)
     */
    @RequiresApi(api = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    public static void register(@NonNull final Application application, final float designSize, final int matchBase,
                                final int matchUnit) {
        if (mActivityLifecycleCallbacks == null) {
            mActivityLifecycleCallbacks =
                    new Application.ActivityLifecycleCallbacks() {
                        @Override
                        public void onActivityCreated(Activity activity,
                                                      Bundle savedInstanceState) {
                            if (activity != null) {
                                match(activity, designSize, matchBase, matchUnit);
                            }
                        }

                        @Override
                        public void onActivityStarted(Activity activity) {

                        }

                        @Override
                        public void onActivityResumed(Activity activity) {

                        }

                        @Override
                        public void onActivityPaused(Activity activity) {

                        }

                        @Override
                        public void onActivityStopped(Activity activity) {

                        }

                        @Override
                        public void onActivitySaveInstanceState(Activity activity,
                                                                Bundle outState) {

                        }

                        @Override
                        public void onActivityDestroyed(Activity activity) {

                        }
                    };
            application.registerActivityLifecycleCallbacks(
                    mActivityLifecycleCallbacks);
        }
    }

    /**
     * 全局取消所有的适配
     */
    @RequiresApi(api = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    public static void unregister(@NonNull final Application application, @NonNull int... matchUnit) {
        if (mActivityLifecycleCallbacks != null) {
            application.unregisterActivityLifecycleCallbacks(
                    mActivityLifecycleCallbacks);
            mActivityLifecycleCallbacks = null;
        }
        for (int unit : matchUnit) {
            cancelMatch(application, unit);
        }
    }

    /**
     * 适配屏幕(放在 Activity 的 setContentView() 之前执行)
     * 此方法适用于已短边为参考系
     *
     * @param context    上下文
     * @param designSize 设计图的尺寸
     */
    public static void match(@NonNull final Context context, final float designSize) {
        if (sMatchInfo.getScreenWidth() > sMatchInfo.getScreenHeight()) {
            match(context, designSize, MATCH_BASE_HEIGHT, MATCH_UNIT_DP);
        } else {
            match(context, designSize, MATCH_BASE_WIDTH, MATCH_UNIT_DP);
        }
    }

    /**
     * 适配屏幕(放在 Activity 的 setContentView() 之前执行)
     *
     * @param context    上下文
     * @param designSize 设计图的尺寸
     * @param matchBase  适配基准
     */
    public static void match(@NonNull final Context context, final float designSize, int matchBase) {
        match(context, designSize, matchBase, MATCH_UNIT_DP);
    }

    /**
     * 适配屏幕(放在 Activity 的 setContentView() 之前执行)
     *
     * @param context    上下文
     * @param designSize 设计图的尺寸
     * @param matchBase  适配基准
     * @param matchUnit  使用的适配单位
     */
    private static void match(@NonNull final Context context, final float designSize, int matchBase, int matchUnit) {
        if (designSize == 0) {
            throw new UnsupportedOperationException(
                    "The designSize cannot be equal to 0");
        }
        if (matchUnit == MATCH_UNIT_DP) {
            matchByDP(context, designSize, matchBase);
        } else if (matchUnit == MATCH_UNIT_PT) {
            matchByPT(context, designSize, matchBase);
        }
    }

    /**
     * 重置适配信息,取消适配
     */
    public static void cancelMatch(@NonNull final Context context) {
        cancelMatch(context, MATCH_UNIT_DP);
        cancelMatch(context, MATCH_UNIT_PT);
    }

    /**
     * 重置适配信息,取消适配
     *
     * @param context   上下文
     * @param matchUnit 需要取消适配的单位
     */
    private static void cancelMatch(@NonNull final Context context, int matchUnit) {
        if (sMatchInfo != null) {
            final DisplayMetrics displayMetrics =
                    context.getResources().getDisplayMetrics();
            if (matchUnit == MATCH_UNIT_DP) {
                if (displayMetrics.density != sMatchInfo.getAppDensity()) {
                    displayMetrics.density = sMatchInfo.getAppDensity();
                }
                if (displayMetrics.densityDpi != sMatchInfo.getAppDensityDpi()) {
                    displayMetrics.densityDpi =
                            (int) sMatchInfo.getAppDensityDpi();
                }
                if (displayMetrics.scaledDensity != sMatchInfo
                        .getAppScaledDensity()) {
                    displayMetrics.scaledDensity =
                            sMatchInfo.getAppScaledDensity();
                }
            } else if (matchUnit == MATCH_UNIT_PT) {
                if (displayMetrics.xdpi != sMatchInfo.getAppXdpi()) {
                    displayMetrics.xdpi = sMatchInfo.getAppXdpi();
                }
            }
        }
    }

    public static MatchInfo getMatchInfo() {
        return sMatchInfo;
    }

    /**
     * 使用 dp 作为适配单位(适合在新项目中使用,在老项目中使用会对原来既有的 dp 值产生影响) <br>
     * <ul>
     * dp 与 px 之间的换算:
     * <li>px = density * dp</li>
     * <li>density = dpi / 160</li>
     * <li>px = dp * (dpi / 160)</li>
     * </ul>
     *
     * @param context    上下文
     * @param designSize 设计图的宽/高(单位: dp)
     * @param base       适配基准
     */
    private static void matchByDP(@NonNull final Context context, final float designSize, int base) {
        final float targetDensity;
        if (base == MATCH_BASE_WIDTH) {
            targetDensity = sMatchInfo.getScreenWidth() * 1f / designSize;
        } else if (base == MATCH_BASE_HEIGHT) {
            targetDensity = sMatchInfo.getScreenHeight() * 1f / designSize;
        } else {
            targetDensity = sMatchInfo.getScreenWidth() * 1f / designSize;
        }
        final int targetDensityDpi = (int) (targetDensity * 160);
        final float targetScaledDensity = targetDensity
                * (sMatchInfo.getAppScaledDensity() / sMatchInfo.getAppDensity());
        final DisplayMetrics displayMetrics =
                context.getResources().getDisplayMetrics();
        displayMetrics.density = targetDensity;
        displayMetrics.densityDpi = targetDensityDpi;
        displayMetrics.scaledDensity = targetScaledDensity;
    }

    /**
     * 使用 pt 作为适配单位(因为 pt 比较冷门,新老项目皆适合使用;也可作为 dp 适配的补充, 在需要同时适配宽度和高度时,使用 pt 来适配
     * dp 未适配的宽度或高度) <br/>
     * <p>
     * pt 转 px 算法: pt * metrics.xdpi * (1.0f/72)
     * </p>
     *
     * @param context    上下文
     * @param designSize 设计图的宽/高(单位: pt)
     * @param base       适配基准
     */
    private static void matchByPT(@NonNull final Context context, final float designSize, int base) {
        final float targetXdpi;
        if (base == MATCH_BASE_WIDTH) {
            targetXdpi = sMatchInfo.getScreenWidth() * 72f / designSize;
        } else if (base == MATCH_BASE_HEIGHT) {
            targetXdpi = sMatchInfo.getScreenHeight() * 72f / designSize;
        } else {
            targetXdpi = sMatchInfo.getScreenWidth() * 72f / designSize;
        }
        final DisplayMetrics displayMetrics =
                context.getResources().getDisplayMetrics();
        displayMetrics.xdpi = targetXdpi;
    }

    /**
     * 适配信息
     */
    private static class MatchInfo {

        private int screenWidth;

        private int screenHeight;

        private float appDensity;

        private float appDensityDpi;

        private float appScaledDensity;

        private float appXdpi;

        int getScreenWidth() {
            return screenWidth;
        }

        void setScreenWidth(int screenWidth) {
            this.screenWidth = screenWidth;
        }

        int getScreenHeight() {
            return screenHeight;
        }

        void setScreenHeight(int screenHeight) {
            this.screenHeight = screenHeight;
        }

        float getAppDensity() {
            return appDensity;
        }

        void setAppDensity(float appDensity) {
            this.appDensity = appDensity;
        }

        float getAppDensityDpi() {
            return appDensityDpi;
        }

        void setAppDensityDpi(float appDensityDpi) {
            this.appDensityDpi = appDensityDpi;
        }

        float getAppScaledDensity() {
            return appScaledDensity;
        }

        void setAppScaledDensity(float appScaledDensity) {
            this.appScaledDensity = appScaledDensity;
        }

        float getAppXdpi() {
            return appXdpi;
        }

        void setAppXdpi(float appXdpi) {
            this.appXdpi = appXdpi;
        }
    }

}

有需要的也可以直接去拿

没更新或者频繁更新的时候都是在认真生活

上一篇下一篇

猜你喜欢

热点阅读