首页 > Activity悬浮并可拖动(访悬浮歌词)

Activity悬浮并可拖动(访悬浮歌词)

强烈推荐:

最无私的Android资料(书籍+代码)分享-不要积分(求置顶)

http://www.eoeandroid.com/thread-80891-1-1.html

大量项目源码分享

http://www.eoeandroid.com/thread-162339-1-1.html

基于Android系统的影音播放器开发

http://www.eoeandroid.com/thread-183130-1-1.html

天天动听, 这款Android手机上的音乐播放器,相信不少朋友都曾用过。 不知大家是否注意到,天天动听有一个迷你歌词的特效。

什么效果呢? 就是不管你切到什么画面, 歌词永远显示,并且可以拖动。 类型QQ音乐,在电脑上播放时显示的歌词效果。

下面先来看一下效果。

 

这个歌词是在所有界面之上的。

下面我们将这个效果解剖一下, 我认为主要有三个难点:

1. 歌词悬浮在所有页面之上

2. 歌词可以拖动位置

3. 歌词的播放效果 (颜色覆盖)

对于第一点,首先想到的就是 WindowManager , 这个类可能不少人都用过, 一般用于获取屏幕宽度、高度,那么这次就要利用这个类来让我们的歌词永远置顶。

通过查看API,我们看到,在WindowManager.LayoutParams类中,有好几个属性可以设置View置顶。

引用

TYPE_SYSTEM_OVERLAYWindow type: system overlay windows, which need to be displayed on top of everything else. TYPE_SYSTEM_ALERTWindow type: system window, such as low power alert. TYPE_PHONEThese windows are normally placed above all applications, but behind the status bar. 

下面我们来测试一下, 通过下面几句代码,就可以让一个View凌驾在所有View之上。

WindowManager wm = (WindowManager)getApplicationContext().getSystemService(WINDOW_SERVICE);   
WindowManager.LayoutParams params = new WindowManager.LayoutParams();   
params.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;   params.width = WindowManager.LayoutParams.WRAP_CONTENT;   
params.height = WindowManager.LayoutParams.WRAP_CONTENT;   TextView tv = new TextView(this);   
wm.addView(tv, params);  

这边需要注意的是, WindowManager也是通过 getSystemService 来获取,但必须先 getApplicationContext, 否则就无效了。

直接WindowManager wm = (WindowManager)getSystemService(WINDOW_SERVICE); 这样是无效的 !! 还有一点就是,别忘了在Manifest.xml中添加权限:

  

现在我们这样做,我们已经可以让歌词永远置顶了。 但是不要得意,现在这样,结果是我们TextView在最顶层了, 然后你就会发现,页面上什么操作都不能做了, 在TextView下面的任何东西,你都点不了。

为了解决这个,我们必须加上flags参数,让当前的View失去焦点,从而让后面的页面获得焦点。代码如下:

 

params.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL | LayoutParams.FLAG_NOT_FOCUSABLE;

 

加上这一句就可以了。

好了,下面要处理的,就是让歌词可以移动。应该如何做呢? 我们知道,想要让一个View对象在页面上可以移动,只要实现其onTouchEvent事件即可。

  下面开始实现第二步: 歌词移动!

首先我们自定义一个TextView类:MyTextView, 该类继承自TextView, 并实现其中的onTouchEvent方法,来看一下代码:

 

@Override  
public boolean onTouchEvent(MotionEvent event) {   //触摸点相对于屏幕左上角坐标   x = event.getRawX();      y = event.getRawY() - TOOL_BAR_HIGH;   Log.d(TAG, "------X: "+ x +"------Y:" + y);   switch(event.getAction()) {   case MotionEvent.ACTION_DOWN:   startX = event.getX();   startY = event.getY();   break;   case MotionEvent.ACTION_MOVE:   updatePosition();   break;   case MotionEvent.ACTION_UP:   updatePosition();   startX = startY = 0;   break;   }   return true;   
}   
//更新浮动窗口位置参数   private void updatePosition(){   // View的当前位置   params.x = (int)( x - startX);   params.y = (int) (y - startY);   wm.updateViewLayout(this, params);   }  

其中getRawX、getRawY用于获取触摸点离屏幕左上角的距离。 而getX、getY用于获取触摸点离textView左上角的距离.两者相减,就是View左上角的坐标了。另外需要注意的是,在显示View这个View的时候,需要正确指定View的x,y坐标,否则拖动时会错位。

WindowManager wm = (WindowManager)getApplicationContext().getSystemService(WINDOW_SERVICE);   WindowManager.LayoutParams params = MyTextView.params;   params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT | WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;   params.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL | LayoutParams.FLAG_NOT_FOCUSABLE;   params.width = WindowManager.LayoutParams.FILL_PARENT;   params.height = WindowManager.LayoutParams.WRAP_CONTENT;   params.alpha = 80;   params.gravity=Gravity.LEFT|Gravity.TOP;   //以屏幕左上角为原点,设置x、y初始值   params.x = 0;   params.y = 0;   tv = new MyTextView(TopFrame.this);   wm.addView(tv, params);

其中下面三句是关键:

params.gravity=Gravity.LEFT|Gravity.TOP;   
幕左上角为原点,设置x、y初始值   
params.x = 0;   
params.y = 0;

现在这样的话,就可以实现View的移动了。

下面实现第三步: 歌词的播放效果。那么本例仅仅做一个循环, 实际音乐播放器要复杂些,需要根据歌剧的长度及时间间隔,来计算歌词的覆盖速度, 再根据这个速度来覆盖歌词,呈现给用户。要实现歌词播放的效果,需要用到画笔Paint, 还要用到Shader, 还有一个就是UI刷新的问题。一起来看下代码:

 

@Override  
protected void onDraw(Canvas canvas) {   // TODO Auto-generated method stub   super.onDraw(canvas);   float1 += 0.001f;   float2 += 0.001f;           if(float2 > 1.0){   float1 = 0.0f;   float2 = 0.01f;   }   this.setText("");   float len = this.getTextSize() * text.length();   Shader shader = new LinearGradient(0, 0, len, 0,    new int[] { Color.YELLOW, Color.RED },  new float[]{float1, float2},   TileMode.CLAMP);   Paint p = new Paint();   p.setShader(shader);   // 下面这句才控制歌词大小   
        p.setTextSize(20f);   p.setTypeface(Typeface.DEFAULT_BOLD);   //此处x,y坐标也要注意,尤其是y坐标,要与字体大小协调   canvas.drawText(text, 0, 20, p);   }  

 

再加上handler, 让他每隔3毫秒画一次, 就有了这个歌词播放的效果。

private Runnable update = new Runnable() {   
public void run() {   MyTextView.this.update();   handler.postDelayed(update, 3);   
}   private void update(){   postInvalidate();   
}  

 

 

 

 

转载于:https://www.cnblogs.com/vus520/archive/2012/08/01/2617977.html

更多相关:

  • app.js App({onLaunch: function() {if (!wx.cloud) {console.error('请使用 2.2.3 或以上的基础库以使用云能力')} else {wx.cloud.init({// env 参数说明:// env 参数决定接下来小程序发起的云开发调用(wx.cloud.xxx...

  • MVC、MVP、MVVM这些模式是为了解决开发过程中的实际问题而提出来的,目前作为主流的几种架构模式而被广泛使用。 一、MVC(Model-View-Controller) MVC是比较直观的架构模式,用户操作->View(负责接收用户的输入操作)->Controller(业务逻辑处理)->Model(数据持久化)->View(将结...

  • *自适应向布局约束的转化关闭*/ #define PREPCONSTRAINTS(VIEW) [VIEW setTranslatesAutoresizingMaskIntoConstraints:NO] #define CONSTRAIN(PARENT, VIEW, FORMAT) [PARENT addConstraints:[N...

  • 英语的重要性,毋庸置疑!尤其对广大职场人士,掌握英语意味着就多了一项竞争的技能。那,对于我们成人来说,时间是最宝贵的。如何短时间内在英语方面有所突破,这是我们最关心的事情。英语学习,到底有没有捷径可以走,是否可以速成?周老师在这里明确告诉大家,英语学习,没有绝对的捷径走,但是可以少走弯路。十多年的教学经验告诉我们,成功的学习方法可以借...

  • 展开全部 其实IDLE提供了一个显32313133353236313431303231363533e78988e69d8331333365663438示所有行和所有字符的功能。 我们打开IDLE shell或者IDLE编辑器,可以看到左下角有个Ln和Col,事实上,Ln是当前光标所在行,Col是当前光标所在列。 我们如果想得到文件代码...

  • 前言[1]从 Main 方法说起[2]走进 Tomcat 内部[3]总结[4]《Java 2019 超神之路》《Dubbo 实现原理与源码解析 —— 精品合集》《Spring 实现原理与源码解析 —— 精品合集》《MyBatis 实现原理与源码解析 —— 精品合集》《Spring MVC 实现原理与源码解析 —— 精品合集》《Spri...

  • 【本文摘要】【注】本文所述内容为学习Yjango《学习观》相关视频之后的总结,观点归Yjango所有,本文仅作为学习之用。阅读本节,会让你对英语这类运动类知识的学习豁然开朗,你会知道英语学习方面,我们的症结所在。学习英语这类运动类知识,需要把握四个原则第一,不要用主动意识。第二,关注于端对端第三,输入输出符合实际情况第四,通过多个例子...

  • 点云PCL免费知识星球,点云论文速读。文章:RGB-D SLAM with Structural Regularities作者:Yanyan Li , Raza Yunus , Nikolas Brasch , Nassir Navab and Federico Tombari编译:点云PCL代码:https://github.co...