自定义PopupWindow

PopupWindow,一个弹出窗口控件,可以用来显示任意View,而且会浮动在当前activity的顶部

自定义PopupWindow。


1.extends PopupWindow

2.构造方法中可以进行一些属性设置


setContentView(View convertView); //设置popupWindow显示的View

getContentView(); //获取popupWindow显示的view

setWidth(mWith); //设置popupWindow的宽度

setHeight(mHeight); //设置popupWindow的高度

设置宽高,也可以在构造方法那里指定好宽高, 除了可以写具体的值,还可以用WRAP_CONTENT或MATCH_PARENT, popupWindow的width和height属性直接和第一层View相对应。

setAnimationStyle(R.style.PopupAnimation); //设置弹出动画

setFocusable(true);

设置焦点,PopupWindow弹出后,所有的触屏和物理按键都由PopupWindows 处理。其他任何事件的响应都必须发生在PopupWindow消失之后,(home 等系统层面的事件除外)。 比如这样一个PopupWindow出现的时候,按back键首先是让PopupWindow消失,第二次按才是退出 activity,准确的说是想退出activity你得首先让PopupWindow消失,因为不并是任何情况下按back PopupWindow都会消失,必须在PopupWindow设置了背景的情况下。

而setFocusable(false); //PopUpWindow只是一个浮现在当前界面上的view而已,不影响当前界面的任何操作,是一个没有存在感的东西

一般情况下setFocusable(true);

setTouchable(true); // 设置popupwindow可点击


要让点击PopupWindow之外的地方PopupWindow消失:

1.setOutsideTouchable(true);

2.调用setBackgroundDrawable(new BitmapDrawable()); 设置背景,为了不影响样式,这个背景是空的。

除此之外,还可以这样写,setBackgroundDrawable(new ColorDrawable(0x00000000));背景不空,但是完全透明

经过实际检验,只要设置了背景,不管有没有设置setOutsideTouchable(true);即使设置了setOutsideTouchable(false);一样能够实现点击PopupWindow之外的地方PopupWindow消失,有点奇葩,不过为了保险起见,还是加上setOutsideTouchable(true);比较好。


PopupWindow还有一个方法,也是用来设置点击PopupWindow外部使得PopupWindow消失的,不过仅仅是实现这个方法是不行的,一样要设置背景才起作用。可是当设置了背景的时候,下面这个方法不管有没有用都能够实现点击PopupWindow外部使得PopupWindow消失,也是够醉。


设置PopupWindow的弹出位置

popupWindow = new SelectPicPopupWindow(参数);

popupWindow.showAtLocation(findViewById(R.id.settings_layout),
Gravity.BOTTOM|Gravity.CENTER_HORIZONTAL, 0, 0);

 //在这里findViewById(R.id.settings_layout)是当前界面的id。


设置了PopupWindow的background,点击Back键或者点击弹窗的外部区域,弹窗就会dismiss.相反,如果不设置PopupWindow的background,那么点击back键和点击弹窗的外部区域,弹窗是不会消失的.

如果我想要一个效果,点击外部区域,弹窗不消失,但是点击事件会向下面的activity传递,比如下面是一个WebView,我想点击里面的链接等.

然后调用setPopupWindowTouchModal(popupWindow, false);就可以了。


不过还有要注意的是:

1.设置了setHeight();假如设置的高度小于屏幕的高,那么透明的那一部分是不属于PopupWindow的。

2.设置setContentView(View v);由于v里面的组件在布局文件里并没有占满整个屏幕,例如只是放在了底部,使得弹出PopupWindow上部分出现了透明,这个透明部分还是属于PopupWindow的,那么要想做到点击透明部分使得PopupWindow消失,又该怎么做呢?

这个也不难,答案如下:

转载请标明出处:http://77blogs.com/?p=29

自动显示隐藏布局的listView

借助View的OnTouchListener接口来监听listView的滑动,通过比较与上次坐标的大小,判断滑动方向,并通过滑动方向来判断是否需显示或者隐藏对应的布局,并且带有动画效果。

1.自动显示隐藏Toolbar

首先给listView增加一个HeaderView,避免第一个Item被Toolbar遮挡。

//R.dimen.abc_action_bar_default_height_material为系统ActionBar的高度

定义一个mTouchSlop变量,获取系统认为的最低滑动距离

属性动画

//上面为位移还有透明度属性动画

使用的时候theme要用NoActionBar的,不然会引起冲突。同时引入编译

2.当要隐藏和显示的组件不是toolbar,而是我们自定义的布局myView时,需要注意一些点,

(1) 布局要用相对布局,让我们自定义的布局悬浮在listView上方。

(2)避免第一个Item被myView遮挡,给listView增加一个HeaderView,此时需要测量myView的高度,要用下面这种方法,把任务post到UI线程中,不然执行会出错。

其他的与toolbar一样

转载请标明出处:http://77blogs.com/?p=27

Android AIDL 使用

一、概述:

AIDL是Android中IPC(Inter-Process Communication)方式中的一种,AIDL是Android Interface definition language的缩写。

其主要作用是用于进程间额通讯。

在Android系统中,每个进程都运行在一块独立的内存中,在其中完成自己的各项活动,与其他进程都分隔开来。可是有时候我们又有应用间进行互动的需求,比较传递数据或者任务委托等,AIDL就是为了满足这种需求而诞生的。通过AIDL,可以在一个进程中获取另一个进程的数据和调用其暴露出来的方法,从而满足进程间通信的需求。
二、语法:
1、支持的数据类型:
  • 八种基本数据类型:byte、char、short、int、long、float、double、boolean
  • String,CharSequence
  • 实现了Parcelable接口的数据类型
  • List 类型。List承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象
  • Map类型。Map承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象

2、

AIDL文件可以分为两类。一类用来声明实现了Parcelable接口的数据类型,以供其他AIDL文件使用那些非默认支持的数据类型。还有一类是用来定义接口方法,声明要暴露哪些接口给客户端调用,定向Tag就是用来标注这些方法的参数值。

 

3、

定向Tag。定向Tag表示在跨进程通信中数据的流向,用于标注方法的参数值,分为 in、out、inout 三种。其中 in 表示数据只能由客户端流向服务端, out 表示数据只能由服务端流向客户端,而 inout 则表示数据可在服务端与客户端之间双向流通。此外,如果AIDL方法接口的参数值类型是:基本数据类型、String、CharSequence或者其他AIDL文件定义的方法接口,那么这些参数值的定向 Tag 默认是且只能是 in,所以除了这些类型外,其他参数值都需要明确标注使用哪种定向Tag。
4、

明确导包。在AIDL文件中需要明确标明引用到的数据类型所在的包名,即使两个文件处在同个包名下。

 

三、编写代码:

创建两个工程,一个作为服务端,一个作为客户端,客户端绑定服务端service,然后调用方法向服务端获取书籍列表,向服务端添加书籍。

 

1、服务端:

(1)、创建aidl文件Book.aidl

创建后便可以在目录里看到aidl文件。

接下来定义Book类,注意Books类的包名必须与Book.aidl包名一样,但是不可与Book.aidl在同一个目录下。

Book.class的代码如下,其必须继承Parcelable接口:

 

接下来修改Book.aidl文件,将其声明为parcelable类型,并且需要注意的是,原先默认的interface接口需要去掉,否则编译会报错。

 

接下来便是要定义服务端暴露给客户端的接口了(获取书籍列表,添加书籍)

在同样的目录定义aidl文件BookManager.aidl

 

代码如下:

 

注意要把包手动导进来。

接下来,make project便可以看到aidl编译成代码文件

 

这个文件才是我们真正需要用到的。

(2)、创建Service,供客户端绑定

Manifests文件中可以这样写:

 

 onBind方法返回的是BookManager.Stub对象,实现里面的两个方法,客户端拿到这个对象后就可以与服务端通讯了。

 

2、客户端

(1)

将aidl文件与Book.class拷贝到客户端的工程,注意他们的目录需要与服务端的一样,也就是说aidl与Book.class包名要与服务端的一样。

 

make project一下便会生成编译后的文件

(2)、编写代码,与服务端连接:

 

textView3用于绑定服务端

textView4用于获取服务端书籍列表

textView5用于向服务端添加书籍

 

 转载请标明出处:http://77blogs.com/?p=293

参考:https://www.jianshu.com/p/29999c1a93cd

 

 

解决Android编译时出现aapt.exe finished with non-zero exit value 1(第二篇)

转载请标明出处,违权必究:http://77blogs.com/?p=294

之前出现该错误,我用的是这个方法:

https://www.cnblogs.com/tangZH/p/10691383.html

然而遗憾的是,这次不管用了,无奈,只好另寻他法,其实会出现这个错误就是资源文件出现问题,导致无法被打包。

从具体的错误里面也可以看出,确实是资源文件出了问题

 

点击右上角gradle:

 

other里面找到相应的模块,点击运行

然后便可以打印出了错误信息。

 

解决Error:All flavors must now belong to a named flavor dimension. Learn more at…

转载请标明出处:http://77blogs.com/?p=297

低版本的gradle里面不会出现这个错误,高版本出现,不多说,看如何解决

在defaultConfig{}中添加:

flavorDimensions “default”

保证所有的flavor 都属于同一个维度

 

 

Cannot set the value of read-only property ‘outputFile’ for ApkVariantOutputImpl_Decorated{…

转载请标明出处:http://77blogs.com/?p=298

在做多渠道打包的时候出现了这个错误,在高版本的gradle出现。

 

具体错误为:Cannot set the value of read-only property ‘outputFile’ for ApkVariantOutputImpl_Decorated{apkData=Main{type=MAIN, fullName=debug, filters=[]}} of type com.android.build.gradle.internal.api.ApkVariantOutputImpl.
我的代码为下:

 

这个在低版本的gradle是行得通的,但是高版本就不行。

高版本的应该这样:

 

variant.outputs.each改为variant.outputs.all

output.outputFile = new File(outputFile.parent, fileName)改为outputFileName = fileName

 

谈谈Fragment中的onActivityResult

大家或许有遇到这个神坑,在Fragment中使用startActivityForResult能够成功,可是在Fragment中的onActivityResult却无法被调用。一不注意就让人一夜愁白了头。苦经探索(当然包括亲爱的百度和谷歌),终于总结出了一些规律。

在Fragment中使用startActivityForResult之后,onActivityResult的调用是从activity中开始的(即会先调用activity中的onActivityResult)。

一.只嵌套了一层Fragment(比如activity中使用了viewPager,viewPager中添加了几个Fragment)

在这种情况下要注意几个点:

1.在Fragment中使用startActivityForResult的时候,不要使用getActivity().startActivityForResult,而是应该直接使startActivityForResult()。

2.如果activity中重写了onActivityResult,那么activity中的onActivityResult一定要加上super.onActivityResult(requestCode, resultCode, data)。

如果违反了上面两种情况,那么onActivityResult只能够传递到activity中的,无法传递到Fragment中的。

没有违反上面两种情况的前提下,可以直接在Fragment中使用startActivityForResult和onActivityResult,和在activity中使用的一样。

 

二.嵌套多层Fragment(比如activity中使用了viewPager,viewPager中添加了几个Fragment,即第一层Fragment。其中一个Fragment又使用了一个ViewPager,这个ViewPager又加入了几个Fragment,即第二层Fragment)

在这种情况下activity中的onActivityResult调用无法传到第二层Fragment中。自己动手丰衣足食,我们只有手动传了。

让activity继承上面的MyBaseFragmentActivity 。这样就手动把onActivityResult的调用传递到每一层的每一个Fragment里面了。然后在每一个Fragment里面重写onActivityResult就行了,然后根据requestCode和resultCode来分别执行对应事件。

当然,不管是哪个Fragment调用startActivityForResult,onActivityResult的调用都会传递到每个Fragment中。

同样需要注意:

1.如果activity中重写了onActivityResult,那么activity中的onActivityResult一定要加上super.onActivityResult(requestCode, resultCode, data),否则也无法传进Fragment中。

 

不过有点值得注意的是:

在所有的Fragment中若是直接使用startActivityForResult(),那么传到activity中的onActivityResult中的requestCode就会不对,resultCode是对的,当然,这样的话传到每个Fragment中的onActivityResult的requestCode也是不对的(这里大家留意一下,评论里有人说传到Fragment中的是对的)。若是用getActivity().startActivityForResult,则传出来的requestCode和rusultCode就都是对的。

当然若是直接按返回键返回,那么会自动给一个resultCode,这个resultCode和我们设定的是不一样的,因此在重写onActivityResult的时候需要判定resultCode。

由于我们是手动将activity中的onActivityResult的调用传进每一层的每一个Fragment中去的,所以不管在Fragment中是使用startActivityForResult(),还是使用getActivity().startActivityForResult,都没关系,使用getActivity().startActivityForResult不会出现activity中onActivityResult中的调用无法传进去的情况。会影响的只有requestCode。

转载请标明出处,维权必究:http://77blogs.com/?p=11

 

 

解决Android编译时出现aapt.exe finished with non-zero exit value 1

当出现这个错误的时候,说明了你的资源文件出错了。然而AS能给你提供的信息实在太少,看了半天没看出个所以然,也没有说明是哪个资源文件出错,一头雾水。

这时候就可以用

Gradlew

来调试。

而gradlew命令需要java环境,所以我们需要配置JDK和jre环境变量,过程就不说了。

若是已经配置好了java环境,便可使用Android Studio自带的终端进行调试:

此时可以看到一些java信息。

接下来输入一条非常关键的指令:

gradlew processDebugResources --debug

 

然后项目开始编译,屏幕上输出大量编译Log信息

将其全部拷贝到Notepad++,然后搜索:aapt

然后看查找到的appt错误提示是什么,从中可以看到是哪个资源文件出错。

 

转载请标明出处:http://77blogs.com/?p=300

参考文章:https://blog.csdn.net/qq_24118527/article/details/83586161

 

自定义Json解析工具

此博客为博主原创文章,转载请标明出处,维权必究:http://77blogs.com/?p=301

fastjson是很好用的json解析工具,只可惜项目中要求apk体积尽量小,所以并不打算引入fastJson,只好自己写一个,遗憾的是写出的这个并没法解析所有的json数据,不过还是很值得学习的,且听我一一道来。

主要实现两个功能:

1、将jsonArray解析为List

2、将json数据转化为class

当然,class里面的成员变量的名称需要与json里面的key一样。

 

思路:

1、通过反射获取class类里面的成员变量名称以及类型

2、通过成员变量的名称与类型去json数据中获取该key对应的value

2、将value通过反射赋值给class对象。

 

具体且看:

1、定义一个实体类保存class里面的反射获取到的每个成员变量对应字段,名称,类型

 

2、将json数据转换为实体类

 

2.1 取出实体类中的属性,根据名称与类型去jsonObject中取值

 

2.2 给实体类赋值

 

2.3 JsonArrayToList方法

 

3、将jsonArray转为list,注意参数json是jsonArray数据,原理类似,就不再多讲