前言
事情是这样的,因为我们是做游戏产品,关于未成年政策相关的限制,又有新的指示,因此服务端改了接口后,前端有个适配问题就非常影响UI。
咦,用Toast展示长文本,怎么显示不全了。
一查才发现,原来谷歌在安卓12,targetSdkVersion>31后,做了调整。
对于长文本的展示,不建议用Toast了,但是没办法,我又不太能和项目组解释,改用弹窗也不合适,只能想着适配去改改了,既然别的实现方法都走不通,那就想办法吧,自定义Toast?
也对,毕竟Toast提供了setView方法,做一个layout放进去,就行了。这里直接贴代码
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.os.Build;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;
import android.widget.Toast;
public class BToast extends Toast {
private BToast(Context context) {
super(context);
}
private static BToast toast;
private static void cancelToast() {
//为什么把这个if语句去掉,就会异常终止呢?
//因为程序第一次进来时, toast时为空的,第二次及以后, 它才不为空,才能执行toast.cancel()。
if (toast != null) {
toast.cancel();
}
}
public void cancel() {
super.cancel();
}
public void show() {
super.show();
}
public static void initToast( Context context, CharSequence text,boolean NavigationBar) {
//第二次点击及以后,它会先取消上一次的Toast, 然后show本次的Toast。
cancelToast();
toast = new BToast(context);
View mView = LayoutInflater.from(context).inflate(RGet.$L("tc_activity_toast"), null);
TextView mText = mView.findViewById(RGet.$ID("toast_show"));
mText.setText(text);
toast.setView(mView);
int height = 0;
if(NavigationBar){
height = getNavigationBarHeight(context)/2;
}
Log.d("BToast",height+"");
toast.setGravity(Gravity.TOP, -height, 70);
toast.setDuration(Toast.LENGTH_LONG);
toast.show();
}
//屏幕高度
public static int getHeight(Activity activity) {
DisplayMetrics dm = new DisplayMetrics();
WindowManager windowManager = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE);
windowManager.getDefaultDisplay().getMetrics(dm);
return dm.widthPixels;
}
//真实高度
public static int getRealHeight(Activity activity) {
WindowManager windowManager = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE);
Display display = windowManager.getDefaultDisplay();
DisplayMetrics dm = new DisplayMetrics();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
display.getRealMetrics(dm);
} else {
display.getMetrics(dm);
}
int realHeight = dm.widthPixels;
return realHeight;
}
public static int getNavigationBarHeight(Context context) {
Resources resources = context.getResources();
int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
return resourceId != 0 ? resources.getDimensionPixelSize(resourceId) : 0;
}
layout布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/toast_backgound"
>
<TextView
android:id="@+id/toast_show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:padding="8dp"
android:text=""
android:textColor="#000000"
android:gravity="center"
android:textSize="14sp" />
</LinearLayout>
toast_backgound.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="10dp"/>
<solid android:color="#ffffffff"/>
</shape>
调用
BToast.initToast(this,"",isshowNavigationBar);
就是这么简单,但是到这里还没有结束。文本过长的展示是解决了,但是会发现,在有底部导航栏的手机上,Toast 的View没有居中,这……,那再查查资料,发现网上搜的底部导航栏适配也全都返回true,无论有的没有,这可烦死了。在看了这位大佬博客后,最终找到了解决方案。
https://blog.csdn.net/qq_20451879/article/details/79109501
底部虚拟导航栏
注意:指的是当前手机是否设置有虚拟按键!而不是指虚拟按键是否显示!
public static boolean isHaveSoftKey(Activity activity) {
Display d = activity.getWindowManager().getDefaultDisplay();
DisplayMetrics realDisplayMetrics = new DisplayMetrics();
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;
}
底部虚拟按键的高度
public static int getBottomSoftKeysHeight(Activity activity) {
Display d = activity.getWindowManager().getDefaultDisplay();
DisplayMetrics realDisplayMetrics = new DisplayMetrics();
d.getRealMetrics(realDisplayMetrics);
int realHeight = realDisplayMetrics.heightPixels;
DisplayMetrics displayMetrics = new DisplayMetrics();
d.getMetrics(displayMetrics);
int displayHeight = displayMetrics.heightPixels;
return (realHeight - displayHeight);
}
隐藏、显示 - 底部虚拟导航栏
/**
* @param state true 隐藏 false 还原显示
*/
public static void hideBottomMenu(Context context,boolean state){
Intent barIntent = new Intent();
barIntent.setAction("com.alf.switch_status_bar");
barIntent.putExtra("hide", state);
context.sendBroadcast(barIntent);
}
————————————————
版权声明:本文为CSDN博主「Modu_Liu」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_20451879/article/details/79109501
隐藏 - 底部虚拟导航栏
private void hideBottomMenu() {
int flags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_FULLSCREEN |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY |
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(flags);
}
隐藏 - 底部虚拟导航栏
隐藏底部虚拟按键,但是如果你在底部网上滑动还是显示的出来的
private void hideBottomMenu() {
//android 隐藏底部虚拟按键
//隐藏虚拟按键,并且全屏
if (Build.VERSION.SDK_INT > 11 && Build.VERSION.SDK_INT < 19) { // lower api
View v = this.getWindow().getDecorView();
v.setSystemUiVisibility(View.GONE);
} else if (Build.VERSION.SDK_INT >= 19) {
//for new api versions.
View decorView = getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
}
}
关于这个功能我在网上找了很多半成品,大部分都无效,所幸拼拼凑凑实现了此项功能,亲测可用!
下面来贴代码。
NavigationActivity建议:可以将NavigationActivity的关键代码移植到我们项目的BaseActivity,同时此类中的一些Log完全可以删掉,这里打Log只是为了看一些执行流程 ~
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
public class NavigationActivity extends Activity implements ViewTreeObserver.OnGlobalLayoutListener {
FrameLayout content;
private static final String TAG = "BaseActivityForAuto";
private boolean mLayoutComplete = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
content = (FrameLayout) findViewById(android.R.id.content);
content.post(new Runnable() {
@Override
public void run() {
mLayoutComplete = true;
Log.e(TAG, "content 布局完成");
}
});
content.getViewTreeObserver().addOnGlobalLayoutListener(NavigationActivity.this);
}
@Override
public void onGlobalLayout() {
Log.e(TAG, "onGlobalLayout");
if (!mLayoutComplete)
return;
onNavigationBarStatusChanged();
}
protected void onNavigationBarStatusChanged() {
// 子类重写该方法,实现自己的逻辑即可。
}
@Override
protected void onDestroy() {
super.onDestroy();
content.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
}
MainActivity此处的MainActivity替代到对应的需求类即可,但是要记得继承上方的父类 - - ~
因为我们的游戏是横屏,所以这里的判断高度,实质上是宽度。
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.WindowManager;
public class MainActivity extends NavigationActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
boolean isshowNavigationBar = true;
@Override
protected void onNavigationBarStatusChanged() {
super.onNavigationBarStatusChanged();
int displayWidth = BToast.getHeight(this)+BToast.getNavigationBarHeight(this);
int basicWidth = BToast.getRealHeight(this);
Log.e("tag", "宽度" + displayWidth);
Log.e("tag", "真实宽度" + basicWidth);
if (displayWidth < basicWidth) {
isshowNavigationBar = true;
Log.e("tag", "底部导航显示");
} else {
isshowNavigationBar = false;
Log.e("tag", "底部导航隐藏");
}
}
}
总结
通过这个小问题,发现随着安卓版本的更新,行为也发生了很多改变,还是要与时俱进。网上关于底部导航栏的适配有很多文章,但是一试,发现都是一样效果,没什么太大用,可能自己的业务和对方的不一致。总之,还是要感谢Modu_Liu这位大哥,让我成功解决了难题。respect!