今天掐指一算,学习Android长达近两个月了,今天开始,对过去一段时间的学习收获以及遇到的疑难杂症做一些总结。
简单音乐播放器是我自己完成的第一个功能较为完整的APP,可以说是我的Android学习之路上的一个小小里程碑,给我增加了很多信心(~~真容易获得满足~~)。从下面开始,我将详细介绍MusicPlayer的设计过程。
首先,先看一下这个项目的工程目录和运行效果:
从上面的图片看到,整个工程的布局文件有两个:activity_main.xml和musiclist.xml,其中,musiclist.xml中放置了两个TextView,分别对应歌曲名称和演唱者,结合activity_main.xml中的ListView,完成一张音乐文件列表。播放页面的其他组件的布局则由activity_main.xml完成。具体如下:
activity_main.xml:
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
2 xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
3 android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
4 android:paddingRight="@dimen/activity_horizontal_margin"
5 android:paddingTop="@dimen/activity_vertical_margin"
6 android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
7 <LinearLayout
8 android:orientation="vertical"
9 android:layout_width="fill_parent"
10 android:layout_height="fill_parent"
11 android:layout_alignParentBottom="true"
12 android:layout_alignParentStart="true">
13 <LinearLayout
14 android:orientation="vertical"
15 android:layout_width="fill_parent"
16 android:layout_height="match_parent"
17 android:layout_alignParentTop="true"
18 android:layout_alignParentStart="true"
19 android:layout_weight="2">
20
21 <TextView
22 android:layout_width="wrap_content"
23 android:layout_height="wrap_content"
24 android:text="本地音乐文件"
25 android:id="@+id/textView"
26 android:textSize="25dp" />
27
28 <ListView
29 android:layout_width="match_parent"
30 android:layout_height="match_parent"
31 android:id="@android:id/list"
32 android:scrollbars="vertical"
33 android:divider="@android:color/holo_blue_light"
34 android:dividerHeight="2dp"
35 android:drawSelectorOnTop="false"
36 android:choiceMode="singleChoice"/>
37 </LinearLayout>
38
39 <LinearLayout
40 android:orientation="vertical"
41 android:layout_width="fill_parent"
42 android:layout_height="match_parent"
43 android:layout_weight="3">
44
45 <tina.musicplayer.AlwaysMarqueeTextView
46 android:layout_width="100dp"
47 android:layout_height="wrap_content"
48 android:id="@+id/nameDisplay"
49 android:layout_gravity="center_horizontal"
50 android:textSize="28dp"
51 android:ellipsize="marquee"
52 android:marqueeRepeatLimit="marquee_forever"
53 android:focusable="true"
54 android:singleLine="true"
55 android:layout_margin="5dp"/>
56
57 <RelativeLayout
58 android:orientation="horizontal"
59 android:layout_width="match_parent"
60 android:layout_height="wrap_content"
61 android:layout_gravity="center_horizontal">
62 <TextView
63 android:layout_width="wrap_content"
64 android:layout_height="wrap_content"
65 android:text="00:00"
66 android:id="@+id/currTime"
67 android:layout_alignParentStart="true"/>
68
69 <TextView
70 android:layout_width="wrap_content"
71 android:layout_height="wrap_content"
72 android:text="00:00"
73 android:id="@+id/totalTime"
74 android:layout_alignParentEnd="true"/>
75 </RelativeLayout>
76
77 <SeekBar
78 android:layout_width="fill_parent"
79 android:layout_height="wrap_content"
80 android:id="@+id/seekBar"
81 android:layout_gravity="center_horizontal"
82 android:layout_margin="10dp"/>
83
84 <RelativeLayout
85 android:layout_width="match_parent"
86 android:layout_height="wrap_content"
87 android:layout_gravity="center_horizontal"
88 android:layout_margin="20dp">
89
90 <ImageButton
91 android:layout_width="wrap_content"
92 android:layout_height="wrap_content"
93 android:id="@+id/previous"
94 android:layout_gravity="center_horizontal"
95 android:layout_marginStart="40dp"
96 android:src="@drawable/player_previous"
97 android:onClick="onPreviousClick"
98 android:background="@android:color/transparent"
99 android:layout_alignParentTop="true"
100 android:layout_alignParentStart="true" />
101
102 <ImageButton
103 android:layout_width="wrap_content"
104 android:layout_height="wrap_content"
105 android:id="@+id/stop"
106 android:src="@drawable/player_stop"
107 android:layout_gravity="center_horizontal"
108 android:onClick="onStopClick"
109 android:background="@android:color/transparent"
110 android:layout_alignParentTop="true"
111 android:layout_centerHorizontal="true"
112 android:layout_toRightOf="@+id/previous"
113 android:layout_marginStart="30dp"/>
114
115 <ImageButton
116 android:layout_width="wrap_content"
117 android:layout_height="wrap_content"
118 android:id="@+id/play"
119 android:layout_gravity="center_horizontal"
120 android:src="@drawable/player_play"
121 android:onClick="onPlayClick"
122 android:background="@android:color/transparent"
123 android:layout_alignParentTop="true"
124 android:layout_toRightOf="@+id/stop"
125 android:layout_marginStart="30dp"/>
126
127 <ImageButton
128 android:layout_width="wrap_content"
129 android:layout_height="wrap_content"
130 android:layout_gravity="center_horizontal"
131 android:id="@+id/next"
132 android:src="@drawable/player_next"
133 android:onClick="onNextClick"
134 android:background="@android:color/transparent"
135 android:layout_alignParentTop="true"
136 android:layout_toRightOf="@+id/play"
137 android:layout_marginStart="30dp" />
138 </RelativeLayout>
139 </LinearLayout>
140 </LinearLayout>
141 </RelativeLayout>
musiclist.xml:
1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="match_parent" android:layout_height="match_parent"
4 android:orientation="horizontal"
5 android:background="@drawable/selector">
6
7 <TextView
8 android:layout_width="200dp"
9 android:layout_height="wrap_content"
10 android:text="New Text"
11 android:id="@+id/songName"
12 android:textSize="25dp"
13 android:textColor="@android:color/holo_purple"
14 android:layout_weight="2"/>
15
16 <TextView
17 android:layout_width="200dp"
18 android:layout_height="wrap_content"
19 android:text="New Text"
20 android:id="@+id/artistName"
21 android:textSize="25dp"
22 android:gravity="right"
23 android:textColor="@android:color/holo_purple"
24 />
25 </LinearLayout>
预览效果:
在播放页面实现的过程中,主要有以下几个重要的点:
1、自动水平滚动的TextView
为了增加音乐播放器的趣味性,我放置了一个可以水平滚动的TextView,用来显示当前选中的歌曲名称,这也就是常常说的走马灯的文字效果。那么如何实现呢?
首先,新建一个TextView的子类(AlwaysMarqueeTextView),重写isFocusd()方法,使得该类对象始终获得焦点。
1 package tina.musicplayer;
2
3 import android.content.Context;
4 import android.util.AttributeSet;
5 import android.widget.TextView;
6
7 /**
8 * Created by CW3479 on 2015/4/2.
9 */
10 public class AlwaysMarqueeTextView extends TextView {
11 public AlwaysMarqueeTextView(Context context) {
12 super(context);
13 }
14
15 public AlwaysMarqueeTextView(Context context, AttributeSet attrs) {
16 super(context, attrs);
17 }
18
19 public AlwaysMarqueeTextView(Context context, AttributeSet attrs, int defStyleAttr) {
20 super(context, attrs, defStyleAttr);
21 }
22
23 @Override
24 public boolean isFocused() {
25 return true;
26 }
27 }
然后,在布局文件中,放置AlwaysMarqueeTextView,设置属性:
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:focusable="true"
android:singleLine="true"
以上,可以实现程序运行时,选中歌曲,歌曲名就能自动从右往左重复滚动。需要注意的是,只有当AlwaysMarqueeTextView中的文字超过其能够显示的长度时,文字才能开始滚动。所以android:layout_width="100dp"属性需要设置为合适的值。
关于跑马灯效果,还可以参考一下网络上的这篇文章。
2、音乐文件列表
为了完成音乐文件列表的呈现,我用到了ListActivity,在布局文件activity_main.xml中,放置的ListView,设置属性:
androidoid="@android:id/list" 这里的id一定要设置成"@android:id/list",才能使其绑定到ListActivity
android:scrollbars="vertical" 使list长度超过ListView的显示高度时,ListView能够垂直滚动
android:divider="@android:color/holo_blue_light" list中每一行之间的分割线
android:dividerHeight="2dp"
android:choiceMode="singleChoice" 设置选择模式为单选
android:drawSelectorOnTop="false" 使选中某一项时,选中背景不覆盖当前文字使用
现在,我们已经有了ListView和musiclist.xml中的两个TextView,具体如何使用到程序中呢?
(1)定义全局变量
1 private ListView musicListView;
2 private SimpleAdapter listAdapter;
3 private List<HashMap<String,String>> list=new ArrayList<HashMap<String,String>>();
(2)MainActivity继承ListActivity,设置ListAdapter。
1 musicListView=(ListView)findViewById(android.R.id.list);
2 listAdapter=new SimpleAdapter(MainActivity.this,list,R.layout.musiclist,new String[]{"name","artist"}, new int[]{R.id.songName,R.id.artistName});
3 MainActivity.this.setListAdapter(listAdapter);
至此,完成一个音乐播放列表的基本框架。下面,再增加一点小功能。
在点击列表时,我希望能区别出选中的项,即:选中一首歌曲时,该项的背景变成另一种颜色。如何实现这种功能?
(1)在res/drawable文件夹中新建一个selector.xml文件,在里面定义TextView的不同状态下的背景。
(2)在musiclist.xml中,设置LinearLayout的属性android:background="@drawable/selector"
selector.xml:
1 <?xml version="1.0" encoding="utf-8"?>
2 <selector xmlns:android="http://schemas.android.com/apk/res/android">
3 <!--被选中时的布局-->
4 <item
5 android:state_activated="true">
6 <shape>
7 <gradient
8 android:angle="270"
9 android:endColor="#99BD4C"
10 android:startColor="#C1C125"
11 />
12 <corners
13 android:radius="8dp"
14 />
15 </shape>
16 </item>
17 <!--默认的布局-->
18 <item>
19 <shape>
20 <gradient
21 android:angle="270"
22 android:endColor="#A8C3B0"
23 android:startColor="#C0CFCE"
24 />
25 <corners
26 android:radius="8dp"
27 />
28 </shape>
29 </item>
30
31 </selector>
需要注意的是,区分列表项是否选中的属性是:"android:state_activated",当这个属性的值为true时,表明选项被选中。
以上,基本完成了音乐播放器的页面设计。