菜鸡Android学习之路

以下是我在android开发中遇到的问题,顺便记录以下(默认状态栏为沉浸式状态栏)

1.沉浸式状态栏实现

主题布局theme(我喜欢的方式)

    <style name="AppTheme.NoActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>

java代码块

        toolbar = findViewById(R.id.toolbar);
        if (toolbar != null) {
            //设置toolbar高度为本身nav高度+状态栏高度
            final ViewTreeObserver vto = toolbar.getViewTreeObserver();
            //用于监听测量toolbar的宽高
            vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    toolbar.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                    ViewGroup.LayoutParams layoutParams = toolbar.getLayoutParams();
                    layoutParams.height = toolbar.getMeasuredHeight() + ScreenUtils.getStatusHeight(BaseToolbarActivity.this);
                    toolbar.setLayoutParams(layoutParams);
                }
            });
            //设置其paddingTop为状态栏高度(注意没有前面一段话后面你可以试试看效果😀)
            toolbar.setPadding(0, ScreenUtils.getStatusHeight(this), 0, 0);

2.ScrollView+editText出现软键盘遮挡住编辑框

解决软键盘遮挡编辑框同时也不会导致标题栏被顶上去1
下面时某位大佬的源码,大家可以借鉴以下,特别注意不要用NestedScrollView 会出现问题:


import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Build;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.widget.FrameLayout;

import java.lang.reflect.Method;

/**
 * @Description: 用于沉静式状态栏editText被遮挡问题(不能用于首页,会出现底部导航栏被顶起的情况)
 * @Author: yong
 * @time 2020/7/15 18:33
 * @Version: 1.0
 */
public class AndroidBug5497Workaround {

    private final Activity activity;

    // For more information, see https://code.google.com/p/android/issues/detail?id=5497
    // To use this class, simply invoke assistActivity() on an Activity that already has its content view set.

    public static void assistActivity(Activity activity) {
        new AndroidBug5497Workaround(activity);
    }

    private View mChildOfContent;
    private int usableHeightPrevious;
    private FrameLayout.LayoutParams frameLayoutParams;
    private int statusBarHeight;//状态栏高度

    private AndroidBug5497Workaround(final Activity activity) {
        this.activity = activity;
        if (checkDeviceHasNavigationBar(activity)) {
            //获取状态栏的高度
            int resourceId = activity.getResources().getIdentifier("status_bar_height", "dimen", "android");
            statusBarHeight = activity.getResources().getDimensionPixelSize(resourceId);
        }
        //1、找到Activity的最外层布局控件,它其实是一个DecorView,它所用的控件就是FrameLayout
        FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);
        //2、获取到setContentView放进去的View
        mChildOfContent = content.getChildAt(0);
        //3、给Activity的xml布局设置View树监听,当布局有变化,如键盘弹出或收起时,都会回调此监听
        mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            //4、软键盘弹起会使GlobalLayout发生变化
            @Override
            public void onGlobalLayout() {
                //5、当前布局发生变化时,对Activity的xml布局进行重绘
                possiblyResizeChildOfContent(checkDeviceHasNavigationBar(activity));
            }
        });
        //6、获取到Activity的xml布局的放置参数
        frameLayoutParams = (FrameLayout.LayoutParams)
                mChildOfContent.getLayoutParams();
    }

    /**
     * 重新调整布局高度
     * 获取界面可用高度,如果软键盘弹起后,Activity的xml布局可用高度需要减去键盘高度
     *
     * @param hasNav
     */
    private void possiblyResizeChildOfContent(boolean hasNav) {
        //1、获取当前界面可用高度,键盘弹起后,当前界面可用布局会减少键盘的高度
        int usableHeightNow = computeUsableHeight(hasNav);
        //2、如果当前可用高度和原始值不一样
        if (usableHeightNow != usableHeightPrevious) {
            //3、获取Activity中xml中布局在当前界面显示的高度
            int usableHeightSansKeyboard;
            if (hasNav) {
                usableHeightSansKeyboard = mChildOfContent.getHeight();//兼容华为等机型
            } else {
                usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();
                //这个判断是为了解决19之前的版本不支持沉浸式状态栏导致布局显示不完全的问题
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
                    Rect frame = new Rect();
                    activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
                    int statusBarHeight = frame.top;
                    usableHeightSansKeyboard -= statusBarHeight;
                }
            }
            //4、Activity中xml布局的高度-当前可用高度
            int heightDifference = usableHeightSansKeyboard - usableHeightNow;
            //5、高度差大于屏幕1/4时,说明键盘弹出
            if (heightDifference > (usableHeightSansKeyboard / 4)) {
                // keyboard probably just became visible
                // 6、键盘弹出了,Activity的xml布局高度应当减去键盘高度
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && hasNav) {
                    frameLayoutParams.height = usableHeightSansKeyboard - heightDifference + statusBarHeight;
                } else {
                    frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
                }
            } else {
                if (hasNav) {
                    frameLayoutParams.height = usableHeightNow + statusBarHeight;
                } else {
                    frameLayoutParams.height = usableHeightSansKeyboard;
                }
            }
            //7、 重绘Activity的xml布局
            mChildOfContent.requestLayout();
            usableHeightPrevious = usableHeightNow;
        }
    }

    /**
     * 计算mChildOfContent可见高度 ** @return
     */
    private int computeUsableHeight(boolean hasNav) {
        if (hasNav) {
            Rect r = new Rect();
            mChildOfContent.getWindowVisibleDisplayFrame(r);
            // 全屏模式下:直接返回r.bottom,r.top其实是状态栏的高度
            if (r.top < statusBarHeight) {
                return r.bottom - statusBarHeight;
            } else {
                return r.bottom - r.top;
            }
        } else {
            Rect frame = new Rect();
            activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
            int statusBarHeight = frame.top;
            Rect r = new Rect();
            mChildOfContent.getWindowVisibleDisplayFrame(r);

            //这个判断是为了解决19之后的版本在弹出软键盘时,键盘和推上去的布局(adjustResize)之间有黑色区域的问题
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                return (r.bottom - r.top) + statusBarHeight;
            }
            return (r.bottom - r.top);
        }
    }

    /**
     * 通过"qemu.hw.mainkeys"判断是否存在NavigationBar
     *
     * @return 是否有NavigationBar
     */
    private static boolean checkDeviceHasNavigationBar(Activity activity) {
        boolean hasNavigationBar = false;
        Resources rs = activity.getResources();
        int id = rs.getIdentifier("config_showNavigationBar", "bool", "android");
        if (id > 0) {
            hasNavigationBar = rs.getBoolean(id);
        }
        try {
            Class systemPropertiesClass = Class.forName("android.os.SystemProperties");
            Method m = systemPropertiesClass.getMethod("get", String.class);
            String navBarOverride = (String) m.invoke(systemPropertiesClass, "qemu.hw.mainkeys");
            if ("1".equals(navBarOverride)) {
                hasNavigationBar = false;
            } else if ("0".equals(navBarOverride)) {
                hasNavigationBar = true;
            } else {
                hasNavigationBar = hasNavBar(activity);
            }
        } catch (Exception e) {

        }
        return hasNavigationBar;
    }

    /**
     * 根据屏幕真实宽高-可用宽高>0来判断是否存在NavigationBar
     *
     * @param activity 上下文
     * @return 是否有NavigationBar
     */
    private static boolean hasNavBar(Activity activity) {
        WindowManager windowManager = activity.getWindowManager();
        Display d = windowManager.getDefaultDisplay();

        DisplayMetrics realDisplayMetrics = new DisplayMetrics();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            d.getRealMetrics(realDisplayMetrics);
        }

        int realHeight = realDisplayMetrics.heightPixels;
        int realWidth = realDisplayMetrics.widthPixels;

        DisplayMetrics displayMetrics = new DisplayMetrics();
        d.getMetrics(displayMetrics);

        int displayHeight = displayMetrics.heightPixels;
        int displayWidth = displayMetrics.widthPixels;
        return (realWidth - displayWidth) > 0 || (realHeight - displayHeight) > 0;
    }
}

3.android studio报Unknown host 'jcenter.bintray.com'. You may need to adjust the proxy settings in Gradle.

原因:https://jitpack.io被墙了
解决:https://maven.aliyun.com/repository/jcenter引用阿里云的。

4.关于toolbar自定义布局问题

  1. toolbar无法填满左右空白,可以采用以下方法解决(如果你设置了**app:navigationIcon="@mipmap/back"**这个属性你会发现无效果😂)
app:contentInsetEnd="0dp"
app:contentInsetLeft="0dp"
app:contentInsetRight="0dp"
app:contentInsetStart="0dp"
  1. 如果设置了navigationIcon可以用下面这个属性解决
app:contentInsetStartWithNavigation="0dp"

5.ScrollView与NestedScrollView之间使用心得

  1. 沉浸式导航栏下,且里面内容过多且有editText,尽量不要使用NestedScrollView,建议使用ScrollView
  2. 页面内容过多且有recycleView,若想recycleView做到随着里面内容增加而增加,则建议使用NestedScrollView
    以上都是我个人看法,具体情况具体实现,大佬们看到给个建议呗

6.tabLayout取消点击效果阴影

tablayout去掉点击阴影效果

7.关于8.0以上通知栏显示问题

步骤:

  1. 判断是否打开通知栏权限(工具栏Utils)
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;

import androidx.core.app.NotificationManagerCompat;

/**
 * @Description: 判断并请求是否允许通知
 * @Author: yong
 * @time 2020/7/29 18:55
 * @Version: 1.0
 */
public class Utils {

    public static boolean isPermissionOpen(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            return NotificationManagerCompat.from(context).getImportance() != NotificationManager.IMPORTANCE_NONE;
        }
        return NotificationManagerCompat.from(context).areNotificationsEnabled();
    }

    public static void openPermissionSetting(Context context) {
        try {
            Intent localIntent = new Intent();
            localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            //直接跳转到应用通知设置的代码:
            if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                localIntent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
                localIntent.putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName());
                context.startActivity(localIntent);
                return;
            }
            if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                localIntent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
                localIntent.putExtra("app_package", context.getPackageName());
                localIntent.putExtra("app_uid", context.getApplicationInfo().uid);
                context.startActivity(localIntent);
                return;
            }
            if (android.os.Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
                localIntent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                localIntent.addCategory(Intent.CATEGORY_DEFAULT);
                localIntent.setData(Uri.parse("package:" + context.getPackageName()));
                context.startActivity(localIntent);
                return;
            }

            //4.4以下没有从app跳转到应用通知设置页面的Action,可考虑跳转到应用详情页面,

            if (Build.VERSION.SDK_INT >= 9) {
                localIntent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
                localIntent.setData(Uri.fromParts("package", context.getPackageName(), null));
                context.startActivity(localIntent);
                return;
            }

            localIntent.setAction(Intent.ACTION_VIEW);
            localIntent.setClassName("com.android.settings", "com.android.setting.InstalledAppDetails");
            localIntent.putExtra("com.android.settings.ApplicationPkgName", context.getPackageName());


        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(" cxx   pushPermission 有问题");
        }
    }
}
  1. 发送通知(通知栏工具类NotificationUtils)

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.os.Build;

import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;

/**
 * @Description: 通知栏工具类
 * @Author: yong
 * @time 2020/7/29 18:55
 * @Version: 1.0
 */
public class NotificationUtils extends ContextWrapper {

    private int notifyId = 0;
    private String channelId = "0";
    private int smallIcon;
    private String title;
    private String content;
    private NotificationCompat.Builder builder;
    private NotificationManager notificationManager;
    private NotificationManagerCompat notificationManagerCompat;

    private final String[] CHANNEL_NAME = new String[]{
            "常规通知"
    };

    public NotificationUtils(Context context, int smallIcon, String title, String content) {
        this(context, 1, null, smallIcon, title, content);
    }

    public NotificationUtils(Context context, int notifyId, int smallIcon, String title, String content) {
        this(context, notifyId, null, smallIcon, title, content);
    }

    public NotificationUtils(Context context, int notifyId, String channelId, int smallIcon, String title, String content) {
        super(context);
        this.notifyId = notifyId;
        this.channelId = channelId != null ? channelId : this.notifyId + "";
        this.smallIcon = smallIcon;
        this.title = title;
        this.content = content;
        baseNotification();
    }

    private void baseNotification() {
        builder = getBuilder(getApplicationContext(), channelId)
                .setSmallIcon(smallIcon)
                .setContentTitle(title)
                .setContentText(content)
                .setAutoCancel(true);
    }

    private NotificationCompat.Builder getBuilder(Context context, String channelId) {
        return (builder = new NotificationCompat.Builder(context, channelId));
    }

    private NotificationCompat.Builder getBuilder(Context context) {
        return (builder = new NotificationCompat.Builder(context));
    }

    public NotificationCompat.Builder getBuilder() {
        return builder;
    }

    public void notified() {
        notify(builder);
    }

    public void notified(Intent intent) {
        PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, 0);
        notify(builder.setContentIntent(pendingIntent));
    }

    private void notify(NotificationCompat.Builder builder) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            getNotificationManager();
            notificationManager.notify(notifyId, builder.build());
        } else {
            getNotificationManagerCompat();
            notificationManagerCompat.notify(notifyId, builder.build());
        }
    }

    private void getNotificationManager() {
        notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            int importance = NotificationManager.IMPORTANCE_DEFAULT;
            NotificationChannel channel = new NotificationChannel(channelId, CHANNEL_NAME[notifyId], importance);
            //设置震动声音等
            channel.setVibrationPattern(new long[]{0, 1300, 500, 1700});
            notificationManager.createNotificationChannel(channel);
        }
    }

    private void getNotificationManagerCompat() {
        notificationManagerCompat = NotificationManagerCompat.from(getApplicationContext());
    }

    //进度通知栏
    public void notifyProgress(int max, int progress, String title, String content) {
        if (builder != null && progress > 0) {
            builder.setContentTitle(title);
            builder.setContentText(content);
            builder.setProgress(max, progress, false);
            notify();
        }
    }

    public void completeProgress(String title, String content) {
        notifyProgress(0, 0, title, content);
    }


    public void cancel(int notifyId) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            notificationManager.cancel(notifyId);
        } else {
            notificationManagerCompat.cancel(notifyId);
        }
    }

    public NotificationManager getManager() {
        return this.notificationManager;
    }

}

使用:

        //如果通知栏权限已打开
        if (Utils.isPermissionOpen(this)) {
            //发送一条测试通知
            NotificationUtils notificationUtils = new NotificationUtils(this,0,"chanel",R.mipmap.ic_launcher,"title","content");
            notificationUtils.notified();
        }else {
            //跳转到通知界面是否打开通知
            Utils.openPermissionSetting(this);
        }

以上是参考某某大佬的,因为百度的东西太多,忘了具体是谁的,打扰了,打扰了

8.kotlin中onCreateOptionsMenu方法不执行

解决方法:

        //顶部导航栏右侧图标
        val toolbar: Toolbar = findViewById(R.id.toolbar)
        toolbar.inflateMenu(R.menu.add)
        toolbar.setOnMenuItemClickListener { item ->
            when (item.itemId) {
                R.id.add -> CustomToast.INSTANCE.showToast("添加")
            }
            false
        }

未完待续


  1. 该方法用于首页会出现软键盘顶底部导航栏。 ↩︎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值