Android踩坑小记(持续更新)

文章目录


dialog居中问题

android 5.1.1 vivo x7手机弹出Dialog的时候,根布局必须要设置 android:layout_gravity="center" 属性,布局内容才会居中显示,我自己手机是android8.1.0的,不用设置也可以自动居中显示,坑啊…

2019/03/19


dialog适配全面屏

今天测试提了个bug,在刘海屏的手机上弹窗,在底部蒙层没有遮住下面的显示区域,同时弹窗后退到后台再回来会发现dialog样式变了连同下面的Activity的布局也变了. 解决办法如下:


 <style name="myDialog" parent="@android:style/Theme.Dialog">
     <!--Dialog的windowFrame框为无-->
     <item name="android:windowFrame">@null</item>
     <item name="android:windowNoTitle">true</item>
     <item name="android:windowBackground">@color/full_transparent</item>
     <!--是否浮现在activity之上-->
     <item name="android:windowIsFloating">true</item>
     <item name="android:windowContentOverlay">@null</item>
     <!--背景是否模糊显示-->
     <item name="android:backgroundDimEnabled">true</item>

	  <!--**重点在这下面3句**-->
	
     <!--状态栏透明化,解决dialog显示的时候状态栏是黑色的,让dialog布局内容可延伸到状态栏-->
     <item name="android:windowTranslucentStatus">true</item>
     <!--状态栏颜色设置成透明-->
     <item name="android:statusBarColor">@android:color/transparent</item>
     <!--导航透明化,解决dialog显示的时候底部有空白,让dialog布局可延伸到导航栏-->
     <item name="android:windowTranslucentNavigation">true</item>
 </style>

然后在自定义的dialog上使用该样式

public class TabSelectDialog extends Dialog {
  
    public TabSelectDialog(@NonNull Context context) {
        super(context,R.style.myDialog); //这里使用样式
        setContentView(R.layout.dialog_tab_select);
    }
}

还有一个问题就是,虽然布局中已经设置match_parent全屏模式,但是弹出的dialog的布局内容却不是全屏的.因此在自定义的dialog中重写onStart,设置dialog的宽高为全屏模式

@Override
protected void onStart() {
    super.onStart();
    Window window = getWindow();
    WindowManager.LayoutParams lp = window.getAttributes();
    lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
    lp.height = getContext().getResources().getDisplayMetrics().heightPixels;// 用MATCH_PARENT,状态栏和导航栏会覆盖不了
    window.setAttributes(lp);
}

2019/03/22


魅族MX5 显示白色shape无效的问题

该手机必须要设置stroke属性,否则无效

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

    <solid android:color="@color/white"/>
    <corners android:radius="50dp"/>
    <!--魅族mx5必须要弄这个属性,否则看不到效果-->
    <stroke android:color="@color/white" android:width="1px"/>
</shape>

2019/03/25


Android studio Connection timed out: connect

解决方案看这里

手动注释掉下面这2句
在这里插入图片描述
2019/03/27


webview页面软键盘弹出不了

原因看这里

2019/04/02


webview一键登录手机QQ失败

不知道什么时候开始, QQ oauth登陆, 不再让你在网页输入账号密码了. 页面提示正在拉起QQ手机版.然后测试发现点击之后提示qq版本太低,请升级, 一看版本已经是最新的了,这显然有问题.

通过观察webview的shouldOverrideUrlLoading方法返回的url发现,一键登录触发的链接是这样的, 这是在我们的webview加载的苏宁的购物页面中点击qq登录后捕获的url
在这里插入图片描述
可见url的schema并不是http或者https开头的链接地址,而是wtloginmqq ,灵机一动,我想到了通过intent来让系统帮我们跳转到QQ, 思路有了,那就干

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
	 //优先判断qq登录协议
     if (url.startsWith("wtloginmqq://ptlogin/qlogin")) {
         Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
         startActivity(intent);
         return true;
     }
     //然后才是正常的url判断
     if (URLUtil.isNetworkUrl(url)) {
         view.loadUrl(url);
         return true;
     }
     return false;
 }

ok, 搞定.点击一键登录qq成功后会跳去系统默认的浏览器显示苏宁购物的页面操作.

2019/04/03


NestedScrollView+RecycleView滚动的问题

1.滚动不了
检查RecyclerView的高度是不是设置了match_parent,是的话,修改成wrap_content就好了

2.滚动不灵敏
RecycleView需要设置setNestedScrollingEnabled(false)

3.RecycleView抢占焦点
给RecycleView布局设置android:focusableInTouchMode=“false”

2019/04/17

dialog弹窗后导致沉浸栏(statusbar)变黑的问题

修改dialog的高度,将MATCH_PARENT修改成屏幕的真实高度即可.

@Override
protected void onStart() {
    super.onStart();
    Window window = getWindow();
    WindowManager.LayoutParams lp = window.getAttributes();
    lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
    lp.height = getContext().getResources().getDisplayMetrics().heightPixels;//高度为真实高度
    window.setAttributes(lp);
}

另外,dialog想要状态栏透明,还需要设置这些style

<!--状态栏透明-->
<item name="android:windowTranslucentStatus">true</item>
<!--状态栏颜色设置成透明-->
<item name="android:statusBarColor">@android:color/transparent</item>

2019/04/29


app finish 退出应用重启,application的oncreate方法没有重新执行

finish后加上这句 System.exit(0);退出虚拟机,App的进程就会被杀掉.

App退到后台,个推发送通知打开不了目标页,打开的是MainActivity的解决办法

通常情况下,是根据推送协议构建intent,然后再生成PendingIntent,最后Notification的setContentIntent来设置PendingIntent,当点击通知栏的推送通知就可以直接打开inten对应的Activity了. 但是今天测试发现,如果App退到后台时,只能打开MainActivity的神奇现象…

解决办法,创建一个空白的Activity, 启动模式设置为singleTask, 然后收到推送通知的时候,点击时先跳去该空白的Activity, 将推送协议带过去,统一在这个空白的Activity中处理协议跳转目标页,跳过去之后关闭当前的空白页即可.

代码如下:

 @Override
protected void initIntent() {
     super.initIntent();
     //获取推送协议
     String protocol = getIntent().getStringExtra("protocol");
     //根据推送协议生成对应的目标页的intent对象
     Intent target = PushHelper.getIntent(this, protocol);
 	 //启动目标Activity
     startActivity(target);
     //关闭当前空白页
     finish();
     overridePendingTransition(0, 0);
 }

2019/05/16


当RecyclerView遇到Inconsistency detected崩溃时

详情
RecyclerView的Adapter里,发生异常的错误代码如下:

public void notifyData(List<PoiItem> poiItemList) {
    if (poiItemList != null ) {
        mPoiItems.clear();
        mPoiItems.addAll(poiItemList);
        notifyItemRangeChanged(0, poiItemList.size());
    }
}

修复后,运行正常的代码如下:

public void notifyData(List<PoiItem> poiItemList) {
    if (poiItemList != null) {
        int previousSize = mPoiItems.size();
        mPoiItems.clear();
        notifyItemRangeRemoved(0, previousSize);
        mPoiItems.addAll(poiItemList);
        notifyItemRangeInserted(0, poiItemList.size());
    }
}

2019/05/25


解决部分机型的webview goBack方法返回的页面是空白页面

我这里遇到的是使用loadDataWithBaseURL方式来加载网页的情况,问题代码如下:
mWebView.loadDataWithBaseURL(url, pcResponse.getResponse(), “text/html”, “UTF-8”, null);

最后一个参数传了null ,查看源码发现他与历史记录有关 ,如果传null,返回历史页面就会看到空白’about:blank’

 /**
     * @param baseUrl the URL to use as the page's base URL. If null defaults to
     *                'about:blank'.
     * @param data a String of data in the given encoding
     * @param mimeType the MIMEType of the data, e.g. 'text/html'. If null,
     *                 defaults to 'text/html'.
     * @param encoding the encoding of the data
     * @param historyUrl the URL to use as the history entry. If null defaults
     *                   to 'about:blank'. If non-null, this must be a valid URL.
     */
    public void loadDataWithBaseURL(String baseUrl, String data,
            String mimeType, String encoding, String historyUrl) {
        checkThread();
        mProvider.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl);
    }

所以只需把最后一个参数填上url即可,例如:
mWebView.loadDataWithBaseURL(url, pcResponse.getResponse(), “text/html”, “UTF-8”, url);

2019/06/03


URLDecoder: Illegal hex characters in escape (%) pattern

解决办法

2019/06/25


NestedScrollView嵌套RecyclerView导致快速滚动列表的时候会停留在列表的顶部

方式一:
在RecycleView的外包裹一个父布局,添加这几个属性, 这种方式比较暴力,会导致EditText获取不了焦点无法点击.

<android.support.constraint.ConstraintLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:descendantFocusability="blocksDescendants"
     android:focusable="true"
     android:focusableInTouchMode="true">
		

</android.support.constraint.ConstraintLayout>

然后RecyclerView设置setNestedScrollingEnabled(false);

方式二:

mSearchEdt.clearFocus();//默认清空EditText的焦点
findViewById(R.id.scroll_view).setOnTouchListener(new View.OnTouchListener() {
   @Override
    public boolean onTouch(View v, MotionEvent event) {
        mSearchEdt.clearFocus(); //触摸列表的时候,清空EditText的焦点
        return false;
    }
});

2019/06/27


JSONObject的optLong()的坑

详情


URL中关于空格的编码转换成+或转换成%20的问题

使用android 提供的Uri.encode方法解决,详情

Android 9 网络适配 network-security-config & cleartextTrafficPermitted

详情


databinding中的TextView设置margin属性

报错

Cannot find the setter for attribute ‘android:layout_marginRight’ with parameter type int on android.widget.TextView.

处理方式参考


Caused by: org.apache.xerces.impl.io.MalformedByteSequenceException: Invalid byte 3 of 3-byte UTF-8

详情


Android 上出现:Type parameter T has incompatible upper bounds: ViewDataBinding 的问题

详情

Missing import expression although it is registered

详情


favicon.ico不存在导致webview#WebViewClient的onReceivedHttpError返回404状态码

参考详情

主要是重写 WebViewClient的这3个方法

	//禁用favicon.ico请求
	@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) //5.0
	@Override
	public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
	    if (!request.isForMainFrame() && request.getUrl().getPath().endsWith("/favicon.ico")) {
	        try {
	            //返回一个本地的favicon.ico
	            return new WebResourceResponse("image/png", null,
	                    new BufferedInputStream(view.getContext().getAssets().open("favicon.ico")));
	        } catch (Exception e) {
	            e.printStackTrace();
	        }
	    }
	    return null;
	}
	@Override
	public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
	    if (url.toLowerCase().contains("/favicon.ico")) {
	        try {
	            return new WebResourceResponse("image/png", null,
	                    new BufferedInputStream(view.getContext().getAssets().open("favicon.ico")));
	        } catch (Exception e) {
	            e.printStackTrace();
	        }
	    }
	    return null;
	}
	//Android6.0以上404或者500处理
	@TargetApi(android.os.Build.VERSION_CODES.M)
	@Override
	public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
	    super.onReceivedHttpError(view, request, errorResponse);
	    int statusCode = errorResponse.getStatusCode();
	    if (!request.isForMainFrame() && request.getUrl().getPath().endsWith("/favicon.ico") ) {
	        Log.e("cys","favicon.ico 请求错误"+errorResponse.getStatusCode()+errorResponse.getReasonPhrase());
	    }else{
	        if (404 == statusCode || 500 == statusCode) {
	            onReceivedError = true;
	            view.loadUrl("about:blank");// 避免出现默认的错误界面
	            mUEView.showError();
	        }
	    }
	}

然后在项目的asserts目录下添加一个favicon.ico文件, 若网页不存在则使用该本地的.


刘海屏如何全屏让布局延伸到状态栏底下

   <style name="AppTheme.FullScreen">
        <item name="windowNoTitle">true</item>
        <item name="android:windowFullscreen">true</item>
        <item name="android:windowTranslucentNavigation">true</item>
        <!--允许页面延伸到刘海区域-->
        <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
    </style>

2020-7-5


androidx.preference.PreferenceScreen 去除左边空白

参考这篇文章

The style on this component requires your app theme to be Theme.MaterialComponents

 Caused by: java.lang.IllegalArgumentException: The style on this component requires your app theme to be Theme.MaterialComponents (or a descendant).
        at com.google.android.material.internal.ThemeEnforcement.checkTheme(ThemeEnforcement.java:248)
        at com.google.android.material.internal.ThemeEnforcement.checkMaterialTheme(ThemeEnforcement.java:222)
        at com.google.android.material.internal.ThemeEnforcement.checkCompatibleTheme(ThemeEnforcement.java:150)
        at com.google.android.material.internal.ThemeEnforcement.obtainStyledAttributes(ThemeEnforcement.java:81)
        at com.google.android.material.button.MaterialButton.<init>(MaterialButton.java:200)
        at com.google.android.material.button.MaterialButton.<init>(MaterialButton.java:191)

解决办法

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">

改成

 <style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">

android 编译突然出错,错误原因 Could not resolve com.tencent.mm.opensdk:wechat-sdk-android-without-mta:+.

解决方案

2020-7-13


微信登录,返回-6错误

解决方案


微信取消分享后还是执行成功函数

原因参考


Cause: invalid type code: 1C

今天在mac上打开AS编译项目出现这个错误,查了下是因为我安装的jdk是14的版本。
解决办法有2种:
1.修改gradle-wrapper.properties中的gradle版本,改为gradle-6.5-all.zip
2.重新下载一个jdk1.8的版本

2020-7-19


ExoPlayerFactory.newSimpleInstance 报错

在这里插入图片描述
原因是需要打开对java8的支持,需要在所有依赖ExoPlayer的build.gradle文件里打开对java8的支持,在android闭包中添加以下代码即可

 compileOptions {
        sourceCompatibility = "1.8"
        targetCompatibility = "1.8"
    }

exoplayer2.upstream.HttpDataSource$InvalidResponseCodeException: Response code 302

原因


Textview做跑马灯出现抖动问题

设置跑马灯效果

 android:ellipsize="marquee"
 android:marqueeRepeatLimit="marquee_forever"
 android:singleLine="true"

解决抖动问题,只需要在外面添加一个LinearLayout父布局即可

<LinearLayout
    android:id="@+id/ll_title"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:paddingRight="20dp"
    app:layout_constraintBottom_toBottomOf="@+id/iv_back"
    app:layout_constraintLeft_toRightOf="@+id/iv_back"
    app:layout_constraintRight_toLeftOf="@+id/iv_more"
    app:layout_constraintTop_toTopOf="@+id/iv_back">
    <TextView
        android:id="@+id/tv_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ellipsize="marquee"
        android:marqueeRepeatLimit="marquee_forever"
        android:singleLine="true"
        android:text="我是标题,让我来回滚起"
        android:textColor="@color/white"
        android:textSize="18sp" />
</LinearLayout>

解决Android10读取不到/sdcard/、/storage/emulated/0/文件的问题

原因
Android Q官方文档
Android Q 分区存储

Android Q文件存储机制修改成了沙盒模式,和IOS神似
应用只能访问自己沙盒下的文件和公共媒体文件
对于Android Q以下,还是使用老的文件存储方式

解决办法:
在AndroidManifest.xml 里的application中添加 android:requestLegacyExternalStorage=“true” 临时解决。可以兼容到Android 11。或者targetsdk 降低到29以下。

<application  
     android:requestLegacyExternalStorage="true">

2020/09/25


java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionBaseViewHolder{d29491a position=4 id=-1, oldPos=-1, pLpos:-1 no parent}

原因是RecycleView数据变动(移除和增加)没有保证Adapter中的数据和外部集合中的数据保持一致导致的同步问题.
参考
链接一
链接二

解决支付宝SDK与友盟推送SDK出现的utdid冲突!

参考

AndroidStudio Build Output乱码解决

参考


Android Studio中Junit单元测试使用JSON对象异常的问题

比如:
JSONObject jsonObject = new JSONObject();

报异常:java.lang.RuntimeException: Method put in org.json.JSONObject not mocked. See https://sites.google.com/a/android.com/tools/tech-docs/unit-testing-support for details.

但是将测试代码放到设备AndroidTest中,使用JSONObject代码时无异常。
原来,JSON包含在Android SDK中,JUnit单元测试无法使用,会抛异常;但可以在AndroidTest中使用,如果要在Junit中使用,需要在App或Library项目的build.gradle中添加依赖:

testCompile files('libs/json-20180813.jar')

这个jar包可以在gradle的缓存中提取出来
在这里插入图片描述


IntelliJ IDEA 运行项目的时候提示 Command line is too long 错误

在执行单元测试的时候提示:

Command line is too long. Shorten command line for Application or also for Spring Boot default configuration.

解决办法如下图所示:
在这里插入图片描述


permission denied for window type 2002解决方法

在android8.0之后,WindowManager.LayoutParams的type需要这样设置

// 设置窗体显示类型
WindowManager.LayoutParams layoutParams= new WindowManager.LayoutParams();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    layoutParams.type =WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} 
else {
    layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
}

ps:在Android6.0之前,如果要弹出全局悬浮窗,只需要在AndroidManifest.xml中申请如下权限即可。

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

但是从Android6.0开始,不仅需要上述权限,还需要动态申请此权限,用户手动开启才行。
处理方法如下:

if (Build.VERSION.SDK_INT >= 23) { // Android6.0及以后需要动态申请权限
  if (!Settings.canDrawOverlays(mContext)) {
    //启动Activity让用户授权
    Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
    startActivityForResult(intent, 1010);
  } else {
    // 弹出悬浮窗
  }
} else {
  // 弹出悬浮窗
}
 
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  if (requestCode == 1010) {
    if (Build.VERSION.SDK_INT >= 23) { // Android6.0及以后需要动态申请权限
      if (Settings.canDrawOverlays(mContext)) {
        // 弹出悬浮窗
      } else {
        Toast.makeText(mContext, "not granted permission!", Toast.LENGTH_SHORT);
      }
    }
  }
}

Lint found fatal errors while assembling a release target.

To proceed, either fix the issues identified by lint, or modify your build script as follows:

android {
lintOptions {
checkReleaseBuilds false
// Or, if you prefer, you can continue to check for errors in release builds,
// but continue the build even when errors are found:
abortOnError false
}
}

意思是可以通过lintOptions来忽略错误:

lintOptions {
	// 遇到lint检查错误是否要终止构建,这里设置false表示不终止
	abortOnError false
	// 是否将警告当作错误来处理
	warningsAsErrors false
	// 是否检查新API
	check 'NewApi'
}

error: style attribute ‘attr/colorPrimary (:attr/colorPrimary)’ not found.

添加依赖即可

dependencies {
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
}

Android Error:Execution failed for task ‘:app:compileDebugJavaWithJavac’ 解决方案

如果是mac或者Linux系统,那么在控制台输入 ./gradlew compileDebugJavaWithJavac --stacktrace 就可以查看是什么原因造成的错误,如果不够权限,那么需要给gradlew文件添加执行权限 chmod u+x gradlew

如果是windows系统,那么使用gradlew.bat compileDebugJavaWithJavac --stacktrace


关于unbindService未调用onServiceDisconnected

1、onServiceDisconnected() 在连接正常关闭的情况下是不会被调用的.

2、该方法只在Service 被破坏了或者被杀死的时候调用. 例如, 系统资源不足, 要关闭一些Services, 刚好连接绑定的 Service 是被关闭者之一, 这个时候onServiceDisconnected() 就会被调用.

android.util.AndroidRuntimeException: requestFeature() must be called before adding content 异常处理

参考

Error running app: Default Activity Not Found

参考

解决项目中使用kotlin不能直接引用xml中id

需要添加kotlin-android-extensions插件
参考

Could not find org.jetbrains.kotlin:kotlin-stdlib-jre7:1.3.20.

在这里插入图片描述
把jre7改成jdk7就ok了

warn: multiple substitutions specified in non-positional format; did you mean to add the formatted=“false” attribute?

解决方案

BottomSheetXXX实现下滑关闭菜单踩坑记

参考

小米手机使用NinePatchDrawable会出现线条的问题解决

如下图所示:
在这里插入图片描述
很明显大按钮会看到有线条,而下面的方式是直接在xml种指定.9图的是没有问题的.
问题代码:

val ninePatchDrawable =
	ResourcesCompat.getDrawable(resources,R.drawable.ic_shape_nine_big,context.theme) as NinePatchDrawable

上面的代码是直接通过getDrawable的方式加载存放在drawable-xxxhdpi文件夹内的.9图然后强转成NinePatchDrawable的

正确的代码:

val  ninePatchDrawable = BitmapFactory.decodeResource(resources, R.drawable.ic_shape_nine_big).run {
                    NinePatchDrawable(resources, this, ninePatchChunk, Rect(), null)
}

通过构造方法NinePatchDrawable来创建NinePatchDrawable才是正道.
有人会说拿到NinePatchDrawable有什么用?
我们可以通过代码调用控件的setBackground方法传递一个NinePatchDrawable, 或者通过ninePatchDrawable的draw方法将.9图绘制到canvas上,将ninePatchDrawable转成bitmap来进行各种操作等等.


ClickableSpan事件和View.onClick()事件冲突

参考


BitmapFactory.decodeResource为null的处理方法之一

参考

FloatingActionButton图标颜色无法修改

参考

导出ANR traces 文件(解决无权限、Permission denied)

参考

解决ViewPager2嵌套ViewPager2,导致内部ViewPager滑动无效的问题

参考

思路就是在内部的ViewPager2中嵌套一个父布局,然后在父布局中处理滑动冲突问题, 我这里写了一个工具类

class ViewPager2ScrollableHost private constructor(
    private val parent: ViewGroup,
    private val childViewPager: ViewPager2,
    context: Context
) {
    private var touchSlop = 0
    private var initialX = 0f
    private var initialY = 0f

    companion object {
        @JvmStatic fun newInstance(
            parent: ViewGroup,
            childViewPager: ViewPager2
        ): ViewPager2ScrollableHost {
            return ViewPager2ScrollableHost(parent, childViewPager, parent.context)
        }
    }
	// 获取父的ViewPager2
    private val parentViewPager: ViewPager2?
        get() {
            var v: View? = parent
            while (v != null && v !is ViewPager2) {
                v = v.parent as? View
            }
            return v as? ViewPager2
        }

    private fun canChildScroll(orientation: Int, delta: Float): Boolean {
        val direction = -delta.sign.toInt()
        return when (orientation) {
            0 -> childViewPager.canScrollHorizontally(direction)
            1 -> childViewPager.canScrollVertically(direction)
            else -> throw IllegalArgumentException()
        }
    }

    init {
        touchSlop = ViewConfiguration.get(context).scaledTouchSlop
    }

    fun onInterceptTouchEvent(e: MotionEvent): Boolean {
        handleInterceptTouchEvent(e)
        return false
    }

    private fun handleInterceptTouchEvent(e: MotionEvent) {
        val orientation = parentViewPager?.orientation ?: return

        // Early return if child can't scroll in same direction as parent
        if (!canChildScroll(orientation, -1f) && !canChildScroll(orientation, 1f)) {
            return
        }

        if (e.action == MotionEvent.ACTION_DOWN) {
            initialX = e.x
            initialY = e.y
            // down事件一定要禁掉父的ViewPager2的拦截
            parent.requestDisallowInterceptTouchEvent(true)
        } else if (e.action == MotionEvent.ACTION_MOVE) {
            val dx = e.x - initialX
            val dy = e.y - initialY
            val isVpHorizontal = orientation == ViewPager2.ORIENTATION_HORIZONTAL

            // assuming ViewPager2 touch-slop is 2x touch-slop of child
            val scaledDx = dx.absoluteValue * if (isVpHorizontal) .5f else 1f
            val scaledDy = dy.absoluteValue * if (isVpHorizontal) 1f else .5f

            if (scaledDx > touchSlop || scaledDy > touchSlop) {
                if (isVpHorizontal == (scaledDy > scaledDx)) {
                    // Gesture is perpendicular, allow all parents to intercept
                    parent.requestDisallowInterceptTouchEvent(false)
                } else {
                    // Gesture is parallel, query child if movement in that direction is possible
                    if (canChildScroll(orientation, if (isVpHorizontal) dx else dy)) {
                        // Child can scroll, disallow all parents to intercept
                        parent.requestDisallowInterceptTouchEvent(true)
                    } else {
                        // Child cannot scroll, allow all parents to intercept
                        parent.requestDisallowInterceptTouchEvent(false)
                    }
                }
            }
        }
    }
}

使用方法如下:

public class MyScrollViewpager extends FrameLayout {

	public MyScrollViewpager(Context context) {
	    this(context, null);
	}
	
	public MyScrollViewpager(Context context, AttributeSet attrs) {
	    this(context, attrs, 0);
	}
	
	public MyScrollViewpager(Context context, AttributeSet attrs, int defStyleAttr) {
	    super(context, attrs, defStyleAttr);
	    init(context);
	}
	
	private void init(Context context) {
	    mPageChangeCallback = new ViewpagerOnPageChangeCallback();
	    // 创建子的ViewPager2
	    mViewPager2 = new ViewPager2(context);
	    mViewPager2.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 
	    	ViewGroup.LayoutParams.MATCH_PARENT));
	    mViewPager2.setOffscreenPageLimit(1);
	    mViewPager2.registerOnPageChangeCallback(mPageChangeCallback);
	    // 添加子的ViewPager2
	    addView(mViewPager2);
	    // 关联当前容器和子的ViewPager2
	    mViewPager2ScrollableHost = ViewPager2ScrollableHost.newInstance(this, mViewPager2);
	}

	@Override 
	public boolean onInterceptTouchEvent(MotionEvent ev) {
	    // 交给ViewPager2ScrollableHost处理事件
	    mViewPager2ScrollableHost.onInterceptTouchEvent(ev);
	    return super.onInterceptTouchEvent(ev);
	}

}

除了上面的方式, 还可以这样处理,在MyScrollViewpager的dispatchTouchEvent做处理

	//上一次x坐标
	private float beforeX;
	
	@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (!getViewPager2().isUserInputEnabled()) {
            return super.dispatchTouchEvent(ev);
        }
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
            	beforeX = ev.getX();
                // down事件需要禁掉父ViewPager2的拦截
                getParent().requestDisallowInterceptTouchEvent(true);
                break;
            case MotionEvent.ACTION_MOVE:
                float motionValue = ev.getX() - beforeX;
                if ("只支持向左滑动") {
                    if (motionValue > 0) {
                        //右滑,让外部的父ViewPager2处理
                        getParent().requestDisallowInterceptTouchEvent(false);
                        return false;
                    }
                } else if ("支持向右滑动") {
                    if (motionValue < 0) {
                        //左滑,让外部的父ViewPager2处理
                        getParent().requestDisallowInterceptTouchEvent(false);
                        return false;
                    }
                }
                beforeX = ev.getX();
                break;
            default:
                break;
        }
        // 注意要返回super,否则事件不会分发到子ViewPager2
        return super.dispatchTouchEvent(ev);
    }

解决mac下AS的git log乱码问题

在这里插入图片描述

解决办法很简单

在这里插入图片描述

点9图的非内容区域也是会占用实际宽高的.

在这里插入图片描述

点9图的上边和左边是限定拉伸区域,下边和右边是限定内容显示区域. 在上图中内容的限制区域刚好是白色的圆角矩形内容,而用红色框框框住的这些距离其实是非内容区域, 但是如果使用该点9图的话,这些非内容区域其实也是占据空间的,也就是说就算你布局中没有设置任何的margin值,但是任然会看到该View距离四周有一点距离.


全屏时导致软键盘弹起会遮挡布局内容处理

在Android实现了沉浸式功能后,在有输入框的界面,当点击输入框弹起输入法时,输入法遮挡住了输入框,或者输入框在底部并没有随着输入法弹起而弹起。虽然Activity设置了

android:windowSoftInputMode="adjustResize"

解决方法:
在EditText的根布局添加android:fitsSystemWindows="true"代码即可解决。

注意:
必须在EditText的根布局添加,如果不是根布局,在其它位置或节点添加,界面会多出一块布局 这块布局和顶部状态栏高度一样 颜色可能也一样。

另一种办法就是不设置全屏,通过修改状态栏颜色改成和布局的颜色一样,这样也可以起到状态栏颜色和布局颜色一样的效果.

使用canvas.drawRoundRect()时,解决四个圆角的线比较粗的问题

参考

java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException解决办法

在这里插入图片描述
把换jdk版本,jdk8 jdk7即可。
在这里插入图片描述

TabLayout的selectTab无效

参考

DialogFragment的一些设置项以及坑

1.show和showNow的注意点
首先说一下结论:在使用过程中尽量使用showNow
现在我们知道:
firstDialog.show(supportFragmentManager, "First")

firstDialog.showNow(supportFragmentManager, "First")
都可以展示dialog,
但在使用它们过程中还有需要注意的地方:

show要比showNow稍微“慢”一点,这导致调用show了后,立刻修改dialog中的view(例如textView修改字符内容)会崩溃,而showNow不会
先在FirstDialogFragment中添加方法:

 fun setContent(text: String) {
      tv_content.text = text
  }

以下代码会崩溃:

  val firstDialog = FirstDialogFragment()
  firstDialog.show(supportFragmentManager, "First")
  firstDialog.setContent("Hello")

以下代码则正常执行(对话框内容被修改为Hello):

  val firstDialog = FirstDialogFragment()
  firstDialog.showNow(supportFragmentManager, "First")
  firstDialog.setContent("Hello")

展示弹窗后fragment对象会添加到activity,showNow会在弹窗dismiss消失后移除fragment,show不会移除。
(以前同一个对象非连续地调用两次show会崩溃,现在不会了,可能是google更新了,使show也在弹窗消失后移除了)

2.不可连续地调用show或者showNow
这个“连续”是指在弹窗还没有消失的时候再次调用
原因其实在2中说了,展示弹窗后fragment对象会添加到activity,而同一个fragment只能添加一次,所以连续调用会崩。
一下代码会崩溃:

   firstDialog.showNow(supportFragmentManager, "First")
   firstDialog.showNow(supportFragmentManager, "First")
   firstDialog.show(supportFragmentManager, "First")
   firstDialog.show(supportFragmentManager, "First")

避免方法也很简单,用isResumed来判断当前dialog是否正在展示

    private fun showFirstDialog() {
        if (firstDialog.isResumed) {
            return
        }
        firstDialog.showNow(supportFragmentManager, "First")
    }

当然也可以不直接return,可以做一些其他业务处理

3.使Dialog不可消失
(1)点击返回键弹窗区域外均不消失
必须在showNow之后才有效

firstDialog.showNow(supportFragmentManager, "First")
firstDialog.dialog?.setCancelable(false) //必须在showNow之后才有效

任何时候都生效

firstDialog.isCancelable=false

(2)点击弹窗区域外不消失 点击返回键消失

 firstDialog.dialog?.setCanceledOnTouchOutside(false)  

ImageView的maxHeight和minHeight无效问题

必须要结合adjustViewBounds使用才行

<ImageView
    android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:adjustViewBounds="true"
     android:maxHeight="164dp"
     android:minHeight="136dp"
     android:scaleType="centerCrop"
     android:src="@drawable/ic_party_matching_bg"
     app:layout_constraintBottom_toBottomOf="parent"
     app:layout_constraintEnd_toEndOf="parent"
     app:layout_constraintTop_toTopOf="parent" />

Fragment使用的各种奔溃异常

参考

1. commit already called
2. Fragment already added
3. This transaction is already being added to the back stack
4. Can not perform this action after onSaveInstanceState
5. FragmentManager is already executing transactions

ConstraintLayout maxWidth无效问题

使用app:layout_constraintWidth_max代替
参考

resolveActivity返回null问题

通常会出现在获取系统的Activity, 例如跳去系统的浏览器等等. 原因:Android 30 及以上就⽆法使⽤该api了。
这里以打开系统浏览器的intent为例,在清单文件中添加:

<!-- Android 11 包可见性 添加意图-->
<queries>
    <intent>
         <action android:name="android.intent.action.VIEW" />
         <data android:scheme="*"/>
     </intent>
 </queries>

关于Context.startForegroundService() did not then call Service.startForeground()的解决办法

参考

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值