Android中歌词显示的实现
2015-05-03 09:10
435 查看
之前想写一个音乐播放器,但是一直不明白歌词应该怎么显示。
用UI Automator观察了一下各大音乐播放器,发现QQ音乐和百度音乐是在ScrollView里显示歌词。不清楚ScrollView里面具体是什么,都支持滑动到某个位置之后跳转播放
Flyme 4自带音乐是在ListView里显示,内部嵌套了多个TextView,一行一行显示歌词,支持滑动到某个位置之后跳转到该位置播放(魅族的UI做得的确很不错)
MIUI 6自带音乐的实现方式略奇葩,在ScrollView里嵌套了三个TextView,分别显示之前的所有歌词,当前显示的歌词和之后的所有歌词。实现起来很容易,但是效果不够理想,也不支持跳转播放
还有其他的实现方式,比如在自定义View里重载onDraw方法,自己绘制歌词……这样比较精确,但要支持滑动之后跳转播放的话难度很大。
还是用ScrollView实现吧……
定义一个LyricView类,用来实现歌词显示及滑动到某个位置之后跳转播放
大概思路是这样:在ScrollView中套一个LinearLayout,LinearLayout中放置三个View:
1.一个空白的View,高度是LyricView高度的一半 2.GridView,只有一列,用来显示歌词内容,但不能滑动 3.一个空白的View,高度是LyricView高度的一半
实现滑动后跳转到某个位置播放,要获取GridView里面每一个TextView的高度,然后通过当前所在位置计算现在在LyricView正中间的是哪一行,也就是要跳转到的行
如果布局文件已经在XML中定义好,要获取一个View的高度,直接调用其getWidth()和getHeight()方法就可以了。但是这里每一个TextView都是动态显示的,没有在XML中进行定义。而且每个TextView的高度可能会随歌词长度变化而变化。
最大的难点在于,每个View的实际高度只能在ViewGroup的onLayout方法执行完毕之后才能获取。然而直接获取GridView或ListView的适配器中,getView方法返回的View的高度是不正确的。(这时候获取的高度都是0,因为getView方法返回的对象实际上还没有被显示。)
要获取每个View的正确高度,要通过android.view.ViewTreeObserver类实现。
源码中对ViewTreeObserver的说明:
注册监听器,用于监听view tree中的全局变化。这样的全局事件包括但不限于整个view树的显示,绘制过程的开始和触控模式变化
ViewTreeObserver对象不能通过应用进行实例化,因为它是通过view层次提供的。
获取View对应的ViewTreeObserver,然后添加ViewTreeObserver.OnGlobalLayoutListener可实现在onLayout执行完毕之后,获取View的正确大小。
重写GridView的Adapter中的getView方法,添加OnGlobalLayoutListener获取每行高度。
直接将GridView嵌套进LinearLayout的话,只能看到一行内容。
第二个难点在于,如何让GridView不滑动,也就是平铺显示所有内容。
重载GridView的onMeasure方法:
过了5个月终于把代码传上去了= =
Demo: https://github.com/entalent/LyricViewDemo
用UI Automator观察了一下各大音乐播放器,发现QQ音乐和百度音乐是在ScrollView里显示歌词。不清楚ScrollView里面具体是什么,都支持滑动到某个位置之后跳转播放
Flyme 4自带音乐是在ListView里显示,内部嵌套了多个TextView,一行一行显示歌词,支持滑动到某个位置之后跳转到该位置播放(魅族的UI做得的确很不错)
MIUI 6自带音乐的实现方式略奇葩,在ScrollView里嵌套了三个TextView,分别显示之前的所有歌词,当前显示的歌词和之后的所有歌词。实现起来很容易,但是效果不够理想,也不支持跳转播放
还有其他的实现方式,比如在自定义View里重载onDraw方法,自己绘制歌词……这样比较精确,但要支持滑动之后跳转播放的话难度很大。
还是用ScrollView实现吧……
定义一个LyricView类,用来实现歌词显示及滑动到某个位置之后跳转播放
大概思路是这样:在ScrollView中套一个LinearLayout,LinearLayout中放置三个View:
1.一个空白的View,高度是LyricView高度的一半 2.GridView,只有一列,用来显示歌词内容,但不能滑动 3.一个空白的View,高度是LyricView高度的一半
实现滑动后跳转到某个位置播放,要获取GridView里面每一个TextView的高度,然后通过当前所在位置计算现在在LyricView正中间的是哪一行,也就是要跳转到的行
如果布局文件已经在XML中定义好,要获取一个View的高度,直接调用其getWidth()和getHeight()方法就可以了。但是这里每一个TextView都是动态显示的,没有在XML中进行定义。而且每个TextView的高度可能会随歌词长度变化而变化。
最大的难点在于,每个View的实际高度只能在ViewGroup的onLayout方法执行完毕之后才能获取。然而直接获取GridView或ListView的适配器中,getView方法返回的View的高度是不正确的。(这时候获取的高度都是0,因为getView方法返回的对象实际上还没有被显示。)
要获取每个View的正确高度,要通过android.view.ViewTreeObserver类实现。
源码中对ViewTreeObserver的说明:
/** * A view tree observer is used to register listeners that can be notified of global * changes in the view tree. Such global events include, but are not limited to, * layout of the whole tree, beginning of the drawing pass, touch mode change.... * * A ViewTreeObserver should never be instantiated by applications as it is provided * by the views hierarchy. Refer to {@link android.view.View#getViewTreeObserver()} * for more information. */
注册监听器,用于监听view tree中的全局变化。这样的全局事件包括但不限于整个view树的显示,绘制过程的开始和触控模式变化
ViewTreeObserver对象不能通过应用进行实例化,因为它是通过view层次提供的。
获取View对应的ViewTreeObserver,然后添加ViewTreeObserver.OnGlobalLayoutListener可实现在onLayout执行完毕之后,获取View的正确大小。
重写GridView的Adapter中的getView方法,添加OnGlobalLayoutListener获取每行高度。
@Override public View getView(final int position, View convertView, ViewGroup parent) { final TextView textView = new TextView(context); textView.setText(strs.get(position)); //设置每行的文字居中 textView.setGravity(Gravity.CENTER); //当前位置的文本设为黑色 if(position == currentpos){ textView.setTextColor(Color.BLACK); } //获取TextView对应的ViewTreeObserver final ViewTreeObserver vto = textView.getViewTreeObserver(); //添加OnGlobalLayoutListener,在TextView显示之后获取宽度,高度 vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { textView.getViewTreeObserver().removeGlobalOnLayoutListener(this); int height = textView.getHeight(); int width = textView.getWidth(); heights[position] = height; } }); return textView; }同样的方法也可以用在其他View上。
直接将GridView嵌套进LinearLayout的话,只能看到一行内容。
第二个难点在于,如何让GridView不滑动,也就是平铺显示所有内容。
重载GridView的onMeasure方法:
public class NoScrollGridView extends GridView { public NoScrollGridView(Context context, AttributeSet attrs) { super(context, attrs); } public NoScrollGridView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int expandMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, expandMeasureSpec); } }
过了5个月终于把代码传上去了= =
Demo: https://github.com/entalent/LyricViewDemo
相关文章推荐
- Android中音乐播放器实现歌词同步显示
- Android 实现歌曲播放时歌词同步显示
- Android 实现歌曲播放时歌词同步显示
- Android实现歌曲播放时歌词同步显示具体思路
- Android实现歌词滑动显示
- Android 音乐播放器实现歌词显示
- Android 实现歌曲播放时歌词同步显示
- Android开发本地及网络Mp3音乐播放器(十六)歌词显示及滚动事件实现、ViewPager使用
- Android开发本地及网络Mp3音乐播放器(十六)歌词显示及滚动事件实现、ViewPager使用
- Android实现全屏显示的方法
- Android - 实现图片圆角显示的几种方式
- Android实现图片圆角显示的几种方式
- Android练习项目 Mp3播放器实现 歌词解析(三)
- Android APP安装后不在桌面显示图标的应用场景举例和实现方法
- Android练习项目 Mp3播放器实现 歌词同步播放(四)
- android自定义View实现图片上传进度显示(仿手机QQ上传效果)
- android gridview布局,实现长按某一个,所有项都显示删除的图标
- Android学习系列一用按钮实现显示时间
- Android 实现复制到系统剪贴板 TextView 实现单行输入,禁止换行,多出来的显示省略号
- Android APP安装后不在桌面显示图标的应用场景举例和实现方法