现在手机上的悬浮窗应用越来越多,对用户来说,最常见的悬浮窗应用就是安全软件的悬浮小控件,拿360卫士来说,当开启悬浮窗时,它是一个小球,小球可以拖动,当点击小球出现大窗体控件,可以进行进一步的操作如:释放手机内存等等。于是借着慕课网的视频,仿着实现了360加速球,增加了点击小球进行释放内存的功能。
由于是手机只有频幕截图:实现后如下图所示:点击开启按钮,出现悬浮窗小球控件上面显示手机的可用内存百分比;当拖动小球时,小球变为android图标;松开小球,小球依附在频幕两侧;点击小球,手机底部出现大窗体控件,点击里面的小球,进行手机内存的释放;点击手机屏幕的其他区域,大窗体消失,小球重新出现。
接下来就是实现的一些重要步骤:
1.FloatCircleView的实现(自定义view)
实现FloatCircleView的过程就是自定义view的过程。1、自定义View的属性 2、在View的构造方法中获得我们自定义的属性 3、重写onMesure 4、重写onDraw。我们没有自定义其他属性所以省了好多步骤。
各种变量的初始化,设置拖动小球时要显示的图标,已经计算各种内存。(用于显示在小球上)
public int width=100;
public int heigth=100;
private Paint circlePaint;//画圆
private Paint textPaint; //画字
private float availMemory; //已用内存
private float totalMemory; //总内存
private String text; //显示的已用内存百分比
private boolean isDraging=false; //是否在拖动状态。
private Bitmap src;
private Bitmap scaledBitmap; //缩放后的图片。
/**
* 初始化画笔以及计算可用内存,总内存,和可用内存百分比。
*/
public void initPatints() {
circlePaint = new Paint();
circlePaint.setColor(Color.CYAN);
circlePaint.setAntiAlias(true);
textPaint = new Paint();
textPaint.setColor(Color.WHITE);
textPaint.setTextSize(25);
textPaint.setFakeBoldText(true);
textPaint.setAntiAlias(true);
//设置图片
src = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
//缩放后的图片(将图标设置的和悬浮小球一样大小。)
scaledBitmap = Bitmap.createScaledBitmap(src, width, heigth, true);
//计算已用内存,总内存,已用内存百分比,
availMemory= (float) getAvailMemory(getContext());
totalMemory= (float) getTotalMemory(getContext());
text=(int)((availMemory/totalMemory)*100)+"%";
}
onMeasure();就是将固定的宽高写死,通过
setMeasuredDimension(width, heigth);
传入。
onDraw();进行悬浮小球绘制。定义一个boolean变量判断当前状态是否为拖动小球状态,如果是拖动小球状态,就在该位置绘制android图标,如果不是拖动状态,就进行小球绘制。画小球没有难度,关键是画字。下面的2个图可以加深对画字时的理解。
1.画字时的x坐标(1.textPaint.measureText(text);得到字的宽度
2.小球的宽度/2-字的宽度/2。)
2.画字时的y坐标(1.Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
得到字体属性测量类。2.(fontMetrics.ascent + fontMetrics.descent) / 2
得到字的高度。3.小球的高度/2-字体的高度/2)
画个图就很好理解了:
/**
* 画小球及文字。如果小球是在拖动状态就显示android图标,如果不是拖动状态就显示小球。
* @param canvas
*/
@Override
protected void onDraw(Canvas canvas) {
if (isDraging){
canvas.drawBitmap(scaledBitmap,0,0,null);
}else {
//1.画圆
canvas.drawCircle(width / 2, heigth / 2, width / 2, circlePaint);
//2.画text
float textwidth = textPaint.measureText(text);//文本宽度
float x = width / 2 - textwidth / 2;
Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
float dy = -(fontMetrics.ascent + fontMetrics.descent) / 2;
float y = heigth / 2 + dy;
canvas.drawText(text, x, y, textPaint);
}
}
获得手机已用内存及总内存的方法:
public long getAvailMemory(Context context)
{
// 获取android当前可用内存大小
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
am.getMemoryInfo(mi);
//mi.availMem; 当前系统的可用内存
//return Formatter.formatFileSize(context, mi.availMem);// 将获取的内存大小规格化
return mi.availMem/(1024*1024);
}
public long getTotalMemory(Context context)
{
String str1 = "/proc/meminfo";// 系统内存信息文件
String str2;
String[] arrayOfString;
long initial_memory = 0;
try
{
FileReader localFileReader = new FileReader(str1);
BufferedReader localBufferedReader = new BufferedReader(
localFileReader, 8192);
str2 = localBufferedReader.readLine();// 读取meminfo第一行,系统总内存大小
arrayOfString = str2.split("\\s+");
for (String num : arrayOfString