[置顶] 【android】音乐播放器之UI设计的点点滴滴
2015-10-30 16:06
676 查看
学习Android有一个多月,看完了《第一行代码》以及mars老师的第一期视频通过音乐播放器小项目加深对知识点的理解。从本文开始,将详细的介绍简单仿多米音乐播放器的实现,以及网络解析数据获取百度音乐最新排行音乐以及下载功能。
功能介绍如下:
1、获取本地歌曲列表,实现歌曲播放功能。
2、利用jsoup解析网页数据,从网络获取歌曲列表,同时实现歌曲和歌词下载到手机本地的功能。
3、通知栏提醒,实现仿QQ音乐播放器的通知栏功能.
涉及的技术有:
1、jsoup解析网络网页,从而获取需要的数据
2、android中访问网络,获取文件到本地的网络请求技术,以及下载文件到本地实现断点下载
3、线程池
4、图片缓存
5、service一直在后台运行
6、Activity与Fragment间的切换以及通信
7、notification通知栏设计
8、自定义广播
9、android系统文件管
音乐播放器思路及源码下载见:【android】音乐播放器之设计思路
Ui界面的最终显示效果如下:
马上来看看UI界面是如何实现的,不过先得做些准备工作~~启动界面的设计。细心的朋友肯定注意到目前一些主流app登陆时候都有封面展示的效果,启动界面的制作就是为了实现这个效果:加载一个布局全屏展示一张封面,并2s跳转到主布局MainActivity.
有了上面的准备工作,可以设计主界面以及主界面中的5个Fragment(不是4个嘛!!!!~!~我这边直接将本地音乐列表这个Fragment直接放到MainActivity中)。目前,主流的app主界面实现由四种方式:
(1)ViewPager实现
(2)Fragment实现
(3)FragmentPagerAdapter+ViewPager实现
(4)ViewPagerIndicator+ViewPager实现
就挑个最熟练的实现方式:Fragment实现。(哈哈,目前水平比较低。。。ViewPager后文有使用分析,其余还是想每一种都有机会去尝试用到代码中去。) 小编这边的都是使用动态Fragment
[html] view
plaincopy
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<include layout="@layout/top" />
<FrameLayout
android:id="@+id/id_content"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1">
</FrameLayout>
<include layout="@layout/bottom" />
</LinearLayout>
顶部和底部的布局就补贴出来了,到时直接看源码就明白了。在MainActivity中通过监听底部的按钮获取FragmentManager方式开启一个事务添加一个Fragment或者去隐藏一个Fragment。当然这边也可以直接调用事务的raplace方法替代原布局中的Fragment(~·~后文将介绍相关的Api以及总结Fragment和Activity的通信),主要代码段如下:
[html] view
plaincopy
public void setSelect(int i)
{
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
hideFragment(transaction);
// 把图片设置为亮的
// 设置内容区域
switch (i)
{
case TAB_USER:
if (mTab01 == null)
{
mTab01 = new UserFragment();
transaction.add(R.id.id_content, mTab01);
} else
{
transaction.show(mTab01);
}
mImguser.setImageResource(R.drawable.icon_user_selected);
mTitle.setText("我的音乐");
break;
case TAB_CD:
if (mTab02 == null)
{
mTab02 = new CdFragment();
transaction.add(R.id.id_content, mTab02);
} else
{
transaction.show(mTab02);
}
mImgcd.setImageResource(R.drawable.icon_cd_selected);
mTitle.setText("音乐架");
break;
case TAB_SEARCH:
if (mTab03 == null)
{
mTab03 = new SearchFragment();
transaction.add(R.id.id_content, mTab03);
} else
{
transaction.show(mTab03);
}
mImgsearch.setImageResource(R.drawable.icon_search_selected);
mTitle.setText("搜索");
break;
case TAB_COMPASS:
if (mTab04 == null)
{
mTab04 = new CompassFragment();
transaction.add(R.id.id_content, mTab04);
} else
{
transaction.show(mTab04);
}
mImgcompass.setImageResource(R.drawable.icon_compass_selected);
mTitle.setText("发现");
break;
case TAB_SONGLIST:
if (mTab05 == null)
{
mTab05 = new LocalFragment();
transaction.add(R.id.id_content, mTab05);
} else
{
transaction.show(mTab05);
}
resetImgs();
setVisibility(TOP_MENU);
mTitle.setText("本地音乐");
break;
default:
break;
}
transaction.commit();
}
[html] view
plaincopy
private void hideFragment(FragmentTransaction transaction)
{
setVisibility(TOP_JUMP);
if (mTab01 != null)
{
transaction.hide(mTab01);
}
if (mTab02 != null)
{
transaction.hide(mTab02);
}
if (mTab03 != null)
{
transaction.hide(mTab03);
}
if (mTab04 != null)
{
transaction.hide(mTab04);
}
if (mTab05 != null)
{
transaction.hide(mTab05);
}
}
每个Fragment中的控件也都是最最常用的控件,这边就不一一介绍。。。其余除Ui之外更详细的分析可以看看小编其他相关的博客。其中,应该注意的是:在本地音乐这个Fragment中通过短点击ListView歌曲Items跳转启动PlayAcyivity加载播放界面。也终于到了讲ViewPager这块了!!!~!~
ViewPager添加一个VIew或者删除一个View是通过我们自定义的PagerAdapter控制的,于是我们可以在View中维系一个ArrayList<view>。然后滑动的时候通过get(position)取出对应的view:
ViewPager添加一个VIew或者删除一个View是通过我们自定义的PagerAdapter控制的,于是我们可以在View中维系一个ArrayList<view>。然后滑动的时候通过get(position)取出对应的view:
[html] view
plaincopy
/**
* 初始化viewpager的内容
*/
private void initViewPagerContent() {
View cd = View.inflate(this, R.layout.play_pager_item_1, null);
mCdView = (CDView) cd.findViewById(R.id.play_cdview);
mTextArtistTitle = (TextView) cd.findViewById(R.id.play_singer);
mLrcViewOnFirstPage = (LrcView) cd.findViewById(R.id.play_first_lrc);
View lrcView = View.inflate(this, R.layout.play_pager_item_2, null);
mLrcViewOnSecondPage = (LrcView) lrcView.findViewById(R.id.play_first_lrc_2);
mViewPagerContent.add(cd);
mViewPagerContent.add(lrcView);
}
[html] view
plaincopy
private PagerAdapter mPagerAdapter = new PagerAdapter() {
@Override
public int getCount() {
return mViewPagerContent.size();
}
@Override
public boolean isViewFromObject(View view, Object obj) {
return view == obj;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
container.addView(mViewPagerContent.get(position));
return mViewPagerContent.get(position);
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
((ViewPager) container).removeView((View) object);
}
};
内容太多了,只能讲主要的Ui布局实现。其他细节可以参考我其他博文或者源代码。
下面我想共享下下面的一些关于Fragment的小总结!
Fragment家族常用的API
Fragment常用的三个类:(1)android.app.Fragment 主要用于定义Fragment;(2)android.app.FragmentManager 主要用于在Activity中操作Fragment;(3)android.app.FragmentTransaction
保证一些列Fragment操作的原子性,熟悉事务这个词,一定能明白~
a、获取FragmentManage的方式:getFragmentManager() // v4中,getSupportFragmentManager
b、主要的操作都是FragmentTransaction的方法:1)FragmentTransaction
transaction = fm.benginTransatcion();//开启一个事务;2)transaction.add() 往Activity中添加一个Fragment;3)transaction.remove()从Activity中移除一个Fragment,如果被移除的Fragment没有添加到回退栈(回退栈后面会详细说),这个Fragment实例将会被销毁;4)transaction.replace():使用另一个Fragment替换当前的,实际上就是remove()然后add()的合体~;5)transaction.hide():隐藏当前的Fragment,仅仅是设为不可见,并不会销毁;6)transaction.show():显示之前隐藏的Fragment
7)detach()会将view从UI中移除,和remove()不同,此时fragment的状态依然由FragmentManager维护;8)attach()重建view视图,附加到UI上并显示。
transatcion.commit()//提交一个事务
注意:常用Fragment的哥们,可能会经常遇到这样Activity状态不一致:State loss这样的错误。主要是因为:commit方法一定要在Activity.onSaveInstance()之前调用。
上述,基本是操作Fragment的所有的方式了,在一个事务开启到提交可以进行多个的添加、移除、替换等操作。值得注意的是:如果你喜欢使用Fragment,一定要清楚这些方法,哪个会销毁视图,哪个会销毁实例,哪个仅仅只是隐藏,这样才能更好的使用它们。
功能介绍如下:
1、获取本地歌曲列表,实现歌曲播放功能。
2、利用jsoup解析网页数据,从网络获取歌曲列表,同时实现歌曲和歌词下载到手机本地的功能。
3、通知栏提醒,实现仿QQ音乐播放器的通知栏功能.
涉及的技术有:
1、jsoup解析网络网页,从而获取需要的数据
2、android中访问网络,获取文件到本地的网络请求技术,以及下载文件到本地实现断点下载
3、线程池
4、图片缓存
5、service一直在后台运行
6、Activity与Fragment间的切换以及通信
7、notification通知栏设计
8、自定义广播
9、android系统文件管
音乐播放器思路及源码下载见:【android】音乐播放器之设计思路
Ui界面的最终显示效果如下:
马上来看看UI界面是如何实现的,不过先得做些准备工作~~启动界面的设计。细心的朋友肯定注意到目前一些主流app登陆时候都有封面展示的效果,启动界面的制作就是为了实现这个效果:加载一个布局全屏展示一张封面,并2s跳转到主布局MainActivity.
public class SplashActivity extends Activity{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // no title requestWindowFeature(Window.FEATURE_NO_TITLE); // 全屏 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(R.layout.splash_layout); // 2s跳转到主界面 new Handler().postDelayed(new Runnable() { @Override public void run() { startActivity(new Intent(SplashActivity.this, MainActivity.class)); finish(); } }, 2000); } }
有了上面的准备工作,可以设计主界面以及主界面中的5个Fragment(不是4个嘛!!!!~!~我这边直接将本地音乐列表这个Fragment直接放到MainActivity中)。目前,主流的app主界面实现由四种方式:
(1)ViewPager实现
(2)Fragment实现
(3)FragmentPagerAdapter+ViewPager实现
(4)ViewPagerIndicator+ViewPager实现
就挑个最熟练的实现方式:Fragment实现。(哈哈,目前水平比较低。。。ViewPager后文有使用分析,其余还是想每一种都有机会去尝试用到代码中去。) 小编这边的都是使用动态Fragment
[html] view
plaincopy
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<include layout="@layout/top" />
<FrameLayout
android:id="@+id/id_content"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1">
</FrameLayout>
<include layout="@layout/bottom" />
</LinearLayout>
顶部和底部的布局就补贴出来了,到时直接看源码就明白了。在MainActivity中通过监听底部的按钮获取FragmentManager方式开启一个事务添加一个Fragment或者去隐藏一个Fragment。当然这边也可以直接调用事务的raplace方法替代原布局中的Fragment(~·~后文将介绍相关的Api以及总结Fragment和Activity的通信),主要代码段如下:
[html] view
plaincopy
public void setSelect(int i)
{
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
hideFragment(transaction);
// 把图片设置为亮的
// 设置内容区域
switch (i)
{
case TAB_USER:
if (mTab01 == null)
{
mTab01 = new UserFragment();
transaction.add(R.id.id_content, mTab01);
} else
{
transaction.show(mTab01);
}
mImguser.setImageResource(R.drawable.icon_user_selected);
mTitle.setText("我的音乐");
break;
case TAB_CD:
if (mTab02 == null)
{
mTab02 = new CdFragment();
transaction.add(R.id.id_content, mTab02);
} else
{
transaction.show(mTab02);
}
mImgcd.setImageResource(R.drawable.icon_cd_selected);
mTitle.setText("音乐架");
break;
case TAB_SEARCH:
if (mTab03 == null)
{
mTab03 = new SearchFragment();
transaction.add(R.id.id_content, mTab03);
} else
{
transaction.show(mTab03);
}
mImgsearch.setImageResource(R.drawable.icon_search_selected);
mTitle.setText("搜索");
break;
case TAB_COMPASS:
if (mTab04 == null)
{
mTab04 = new CompassFragment();
transaction.add(R.id.id_content, mTab04);
} else
{
transaction.show(mTab04);
}
mImgcompass.setImageResource(R.drawable.icon_compass_selected);
mTitle.setText("发现");
break;
case TAB_SONGLIST:
if (mTab05 == null)
{
mTab05 = new LocalFragment();
transaction.add(R.id.id_content, mTab05);
} else
{
transaction.show(mTab05);
}
resetImgs();
setVisibility(TOP_MENU);
mTitle.setText("本地音乐");
break;
default:
break;
}
transaction.commit();
}
[html] view
plaincopy
private void hideFragment(FragmentTransaction transaction)
{
setVisibility(TOP_JUMP);
if (mTab01 != null)
{
transaction.hide(mTab01);
}
if (mTab02 != null)
{
transaction.hide(mTab02);
}
if (mTab03 != null)
{
transaction.hide(mTab03);
}
if (mTab04 != null)
{
transaction.hide(mTab04);
}
if (mTab05 != null)
{
transaction.hide(mTab05);
}
}
每个Fragment中的控件也都是最最常用的控件,这边就不一一介绍。。。其余除Ui之外更详细的分析可以看看小编其他相关的博客。其中,应该注意的是:在本地音乐这个Fragment中通过短点击ListView歌曲Items跳转启动PlayAcyivity加载播放界面。也终于到了讲ViewPager这块了!!!~!~
ViewPager添加一个VIew或者删除一个View是通过我们自定义的PagerAdapter控制的,于是我们可以在View中维系一个ArrayList<view>。然后滑动的时候通过get(position)取出对应的view:
ViewPager添加一个VIew或者删除一个View是通过我们自定义的PagerAdapter控制的,于是我们可以在View中维系一个ArrayList<view>。然后滑动的时候通过get(position)取出对应的view:
[html] view
plaincopy
/**
* 初始化viewpager的内容
*/
private void initViewPagerContent() {
View cd = View.inflate(this, R.layout.play_pager_item_1, null);
mCdView = (CDView) cd.findViewById(R.id.play_cdview);
mTextArtistTitle = (TextView) cd.findViewById(R.id.play_singer);
mLrcViewOnFirstPage = (LrcView) cd.findViewById(R.id.play_first_lrc);
View lrcView = View.inflate(this, R.layout.play_pager_item_2, null);
mLrcViewOnSecondPage = (LrcView) lrcView.findViewById(R.id.play_first_lrc_2);
mViewPagerContent.add(cd);
mViewPagerContent.add(lrcView);
}
[html] view
plaincopy
private PagerAdapter mPagerAdapter = new PagerAdapter() {
@Override
public int getCount() {
return mViewPagerContent.size();
}
@Override
public boolean isViewFromObject(View view, Object obj) {
return view == obj;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
container.addView(mViewPagerContent.get(position));
return mViewPagerContent.get(position);
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
((ViewPager) container).removeView((View) object);
}
};
内容太多了,只能讲主要的Ui布局实现。其他细节可以参考我其他博文或者源代码。
下面我想共享下下面的一些关于Fragment的小总结!
Fragment家族常用的API
Fragment常用的三个类:(1)android.app.Fragment 主要用于定义Fragment;(2)android.app.FragmentManager 主要用于在Activity中操作Fragment;(3)android.app.FragmentTransaction
保证一些列Fragment操作的原子性,熟悉事务这个词,一定能明白~
a、获取FragmentManage的方式:getFragmentManager() // v4中,getSupportFragmentManager
b、主要的操作都是FragmentTransaction的方法:1)FragmentTransaction
transaction = fm.benginTransatcion();//开启一个事务;2)transaction.add() 往Activity中添加一个Fragment;3)transaction.remove()从Activity中移除一个Fragment,如果被移除的Fragment没有添加到回退栈(回退栈后面会详细说),这个Fragment实例将会被销毁;4)transaction.replace():使用另一个Fragment替换当前的,实际上就是remove()然后add()的合体~;5)transaction.hide():隐藏当前的Fragment,仅仅是设为不可见,并不会销毁;6)transaction.show():显示之前隐藏的Fragment
7)detach()会将view从UI中移除,和remove()不同,此时fragment的状态依然由FragmentManager维护;8)attach()重建view视图,附加到UI上并显示。
transatcion.commit()//提交一个事务
注意:常用Fragment的哥们,可能会经常遇到这样Activity状态不一致:State loss这样的错误。主要是因为:commit方法一定要在Activity.onSaveInstance()之前调用。
上述,基本是操作Fragment的所有的方式了,在一个事务开启到提交可以进行多个的添加、移除、替换等操作。值得注意的是:如果你喜欢使用Fragment,一定要清楚这些方法,哪个会销毁视图,哪个会销毁实例,哪个仅仅只是隐藏,这样才能更好的使用它们。
相关文章推荐
- java中的合并流SequenceInputStreamDemo
- HDU 1711 Number Sequence(KMP模板)
- druid配置
- UE4 Asynchronous Asset Loading
- EAS BOS序时簿Query显示前字段值更新
- android5.1_SystemUI启动流程
- UITableview
- uva 11538 Chess Queen
- UITableView Plain下的section取消顶部粘连
- UITableViewCell 的Separator 间隔线
- UITableViewCell 的Separator 间隔线
- Implement Queue using Stacks leetcode
- Unique Paths
- 如何解决css帧keyframes在yuicompressor下压缩问题
- POJ 3080 Blue Jeans (暴力)
- UIImagePickerController 拍照
- iOS8中提示框的使用UIAlertController(UIAlertView和UIActionSheet二合一)
- iOS UITableView设置表头和表脚
- UE3常见技术问题
- EasyUI中dialog中嵌入form细节问题记录