悬浮窗实现原理:
悬浮窗要实现,需要用到几个关键的类。
WindowManager:声明了 addView() 、updateViewLayout()、removeView()三个方法的接口
要创建出悬浮窗:那就得使用addView(布局对象,布局参数)方法
要更新悬浮窗的数据,如实现拖动悬浮框:那就得使用updateViewLayout(View,LayoutParams)方法
this,mParams)
通常悬浮窗显示的数据是要实时更新的,如手机内存情况:可以通过服务开启timer定时执行
要移除悬浮窗:可以使用removeView(布局对象)方法
而WindowManager是一个接口,所以自然需要去找它的实现类
WindowManagerImpl:是WindowManager一个重要的实现类,它主要用于保存每个图层的数据——View[],ViewRoot[],WindowManager.LayoutParams[]
但具体操作悬浮窗时不直接使用它,而是使用它的一个内部类
WindowManagerImpl.CompatModeWrapper:实现了WindowManager接口的WindowManagerImpl内部类,用它来实现悬浮窗的操作
它是不依赖Activity存活的!!所以通过服务和CompatModeWrapper就可以实现悬浮窗!!
而创建的悬浮窗与Home的交互属性,记录在WindowManager.LayoutParams即可,调用addView(布局,WindowManager.LayoutParams)即可!!
Window.LocalWindowManager:隶属于Activity的窗口管理器,它依然是实现了WindowManger接口,在每个ActivityThread创建一个Activity的时候,都会有一个对应的LocalWindowManger
了解了这些之后,实现悬浮窗就不难了,麻烦点在于:
悬浮窗的必要参数(照抄即可),如mParams.type = WindowManager.LayoutParams.TYPE_PHONE表示悬浮窗在Activity上层,在状态栏下层!
拖拽的实现:主要是要考虑需要的参数,以左上角为起点计算等
判断当前是否是桌面:通常需要判断当前是桌面还是其他activity在运行,如果是其他activity在运行的话,就应当将悬浮窗关闭,当是桌面的时候再开启
侧边弹框+淡入淡出效果实现:
靠PopupWindow的setAnimationStyle(动画资源)方法设置动画效果
所以:
①在res下新建anim目录,将动画的配置文件给定义好
1 <?xml version="1.0" encoding="utf-8"?>
2 <set xmlns:android="http://schemas.android.com/apk/res/android" >
3
4 <!-- 定义从下向上进入的动画 -->
5 <translate
6 android:duration="3000"
7 android:fromYDelta="100%"
8 android:toYDelta="0" />
9
10 <!-- 定义淡入,持续3s完成 -->
11 <alpha
12 android:duration="3000"
13 android:fromAlpha="0.0"
14 android:toAlpha="1.0" />
15
16 </set>
弹出和淡入效果
②在values目录styles.xml中定义动画样式
1 <!-- PopupWindow弹出的效果 -->
2 <style name="AnimationFade">
3 <item name="android:windowEnterAnimation">@anim/in_dntoup</item>
4 <item name="android:windowExitAnimation">@anim/out_uptodn</item>
③给需要的弹窗设置动画效果:popWind.setAnimationStyle(R.style.AnimationFade)
shape画出简单背景,不使用图片:
直接以图片为背景是简易的,这里将以xml的形式构造图片的背景
shape种类:rectagle矩形,oval椭圆,line水平直线,ring环形
常见效果有:渐变gradient、边角corners(可单独设置四个角)、描边stroke(可虚线描边)
1 <?xml version="1.0" encoding="utf-8"?>
2 <shape xmlns:android="http://schemas.android.com/apk/res/android"
3 android:shape="rectangle" >
4
5 <!-- rectangle为矩形,corners设置圆角,可单独设置任意一个角 -->
6 <corners
7 android:radius="8dp"
8 android:topLeftRadius="0dp" />
9
10 <!-- 用solid可以填充单色,这里使用gradient填充渐变色 -->
11 <gradient
12 android:angle="45"
13 android:centerColor="#0f0"
14 android:endColor="#f00"
15 android:startColor="#00f"
16 android:type="linear" />
17
18 <!-- 描边,dash意为破折号,即描边可以是虚线,dashGap表示小短线的间隔距离,dashWidth表示短线长度 -->
19 <stroke
20 android:dashGap="2dp"
21 android:dashWidth="5dp"
22 android:width="2dp"
23 android:color="#a9c" />
24
25 </shape>
float_bg.xml
将xml背景至于drawable文件下,以图片引用的方式一样使用:android:background="@drawable/float_bg"
SeekBar大致使用原理:(略微有点疑惑,再续)
在style里面定义一个parent为Widget.SeekBar的样式,再定义诸如滑块的图片、滑块离进度的中心距(0dip则滑块中心与进度端能对齐)、进度条的最大高度(android:maxHeight)和最小高度、。。
关键的在于progressDrawable:进度的图片,通常可以用两个.9图片通过layer-list叠层的方式实现进度效果
1 <!-- 亮度进度条 -->
2 <style name="Widget.SeekBar.Normal" parent="@android:style/Widget.SeekBar">
3 <item name="android:thumb">@drawable/toggle</item>
4 <item name="android:thumbOffset">0dip</item>
5 <item name="android:maxHeight">3.0dip</item>
6 <item name="android:indeterminateOnly">false</item>
7 <item name="android:indeterminateDrawable">@android:drawable/progress_indeterminate_horizontal</item>
8 <item name="android:progressDrawable">@drawable/seekbar_horizontal</item>
9 <item name="android:minHeight">3.0dip</item>
10 </style>
所以,seekbar_horizontal自然是定义在drawable中的xml文件
1 <!-- seekbar_horizontal.xml -->
2 <?xml version="1.0" encoding="utf-8"?>
3 <layer-list
4 xmlns:android="http://schemas.android.com/apk/res/android">
5 <item android:id="@android:id/background" android:drawable="@drawable/seek_bkg" />
6 <item android:id="@android:id/secondaryProgress">
7 <clip>
8 <shape>
9 <corners android:radius="2.0dip" />
10 <gradient android:startColor="#80ffd300" android:endColor="#a0ffcb00" android:angle="270.0" android:centerY="0.75" android:centerColor="#80ffb600" />
11 </shape>
12 </clip>
13 </item>
14 <item android:id="@android:id/progress">
15 <clip android:drawable="@drawable/seek" />
16 </item>
17 </layer-list>
使用:在布局中像Button控件一样使用,设置进度的最大值,设置样式。。
1 <SeekBar
2 android:id="@+id/seekBar1"
3 android:layout_width="match_parent"
4 android:layout_height="wrap_content"
5 android:max="235"
6 style="@style/Widget.SeekBar.Normal"
7 android:layout_gravity="center_vertical"
8 android:layout_marginLeft="16dp"
9 android:layout_marginRight="16dp"
10 android:layout_weight="1" />
调节系统亮度的实现:
只需要传入Activity和需要的亮度值就可以调整系统亮度了!!所以,如果再监听到seekbar的值(0-235),再加上Android默认的最小值20,就可以正确的调整系统亮度了!!
当然,这里没必要用public静态方法,具体优化细心总结
1 /**
2 * 设置屏幕亮度
3 * @param activity
4 * @param brightness 需要调整到的亮度,传入
5 * @throws SettingNotFoundException
6 */
7 public static void setScreenBrightness(Activity activity, int brightness) throws SettingNotFoundException {
8 WindowManager.LayoutParams lp = activity.getWindow().getAttributes();
9 lp.screenBrightness = brightness / 255.0f; // 固定计算
10 activity.getWindow().setAttributes(lp);
11 Settings.System.putInt(activity.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, brightness);
12 activity.getContentResolver().notifyChange(Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS), null);
13 }