前言介紹見Android音樂播放器(一)—前言
DisplayActivity設計見圖1,實際效果見圖2。圖1的左側是DisplayActivity佈局文件的層次結構。
1.設置主題style.xml
想要使用toolbar首先需要將actionbar置空,在styles.xml中設置AppTheme的parent爲xxxx.NoActionBar。
AppTheme默認在manifest文件中被使用爲application的android:theme屬性。
2.toolbar控件添加
在DisplayActivity的佈局文件中的合適的位置添加toolbar控件。
android:layout_height="?attr/actionBarSize"是設置高度爲系統默認的actionbar的高度,爲56dp。
app:navigationIcon是工具欄最左側的圖標,後續可以在代碼中實現該圖標的點擊事件,比如將它設置爲返回按鈕,在本應用的主界面這裏,設置的是一個菜單圖標,點擊後顯示側邊欄菜單。
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar_activity_display"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="@drawable/menu_gray"
android:background="@color/black_color"
app:title="@string/title_toolbar"
app:titleTextColor="@color/white_color" />
在activity的onCreate()方法中加載該控件:
Toolbar toolbar = findViewById(R.id.toolbar_activity_display);
setSupportActionBar(toolbar);
3.配合DrawerLayout實現側邊欄
在DisplayActivity的最外層的佈局是DrawerLayout,裏面有兩個LinearLayout佈局,第一個是DisplayActivity的正常內容的佈局,第二個是側邊欄的佈局。
側邊欄的初始化在onCreate()方法中調用config_DrawerLayout()方法(自己是實現的方法),代碼如下。
此方法中會用到兩個全局變量,一個是側邊欄控件本身,另一個是用於將側邊欄、toolbar進行聯繫起來、配置側邊欄相關動作事件的類的對象。
private DrawerLayout drawerlayout = null;//側滑欄
private ActionBarDrawerToggle drawerToggle = null;
public void config_DrawerLayout() {
drawerlayout = findViewById(R.id.drawer_layout);
/*後面兩個參數是@StringRes int openDrawerContentDescRes, @StringRes int
closeDrawerContentDescRes根據我看完源碼猜測爲側邊欄打開和關閉時的描述文本信息*/
drawerToggle = new ActionBarDrawerToggle(this, drawerlayout, toolbar, R.string.app_name, R.string.app_name) {
@Override
public void onDrawerOpened(View drawerView) {//完全打開時觸發
super.onDrawerOpened(drawerView);
//Toast.makeText(DisplayActivity.this,"onDrawerOpened",Toast.LENGTH_SHORT).show();
}
@Override
public void onDrawerClosed(View drawerView) {//完全關閉時觸發
super.onDrawerClosed(drawerView);
//Toast.makeText(DisplayActivity.this,"onDrawerClosed",Toast.LENGTH_SHORT).show();
}
/**
* 當抽屜被滑動的時候調用此方法
* slideOffset表示 滑動的幅度(0-1)
*/
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
super.onDrawerSlide(drawerView, slideOffset);
}
/**
* 當抽屜滑動狀態改變的時候被調用
* 狀態值是STATE_IDLE(閒置--0), STATE_DRAGGING(拖拽的--1), STATE_SETTLING(固定--2)中之一。
*具體狀態可以慢慢調試
*/
@Override
public void onDrawerStateChanged(int newState) {
super.onDrawerStateChanged(newState);
}
};
drawerlayout.setDrawerListener(drawerToggle);
//設置toolbar左側圖標點擊打開側滑欄
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (drawerlayout.isDrawerOpen(GravityCompat.START)) {
//Log.w("DisplayActivity", "closeDrawer");
drawerlayout.closeDrawer(GravityCompat.START);
} else {
//Log.w("DisplayActivity", "openDrawer");
drawerlayout.openDrawer(GravityCompat.START);
}
}
});
//配置側滑界面listView
List<DrawerLayoutListViewItem> drawer_list_view_content = new ArrayList<>();
DrawerLayoutListViewItem myLoveSongs = new DrawerLayoutListViewItem(R.drawable.love, "我喜歡的音樂");
DrawerLayoutListViewItem stopWithTime = new DrawerLayoutListViewItem(R.drawable.stop_with_time, "定時停止播放");
DrawerLayoutListViewItem play_mode_select = new DrawerLayoutListViewItem(R.drawable.setting, "播放模式");
DrawerLayoutListViewItem feedback_suggestions = new DrawerLayoutListViewItem(R.drawable.about, "關於");
DrawerLayoutListViewItem exit = new DrawerLayoutListViewItem(R.drawable.exit_2, "退出");
drawer_list_view_content.add(myLoveSongs);
drawer_list_view_content.add(play_mode_select);
drawer_list_view_content.add(stopWithTime);
drawer_list_view_content.add(feedback_suggestions);
drawer_list_view_content.add(exit);
DrawerLayoutListViewAdapter drawer_list_view_adapter = new DrawerLayoutListViewAdapter(DisplayActivity.this, R.layout.drawer_layout_list_item, drawer_list_view_content);
drawer_layout_list_view.setAdapter(drawer_list_view_adapter);
}
DrawerLayoutListViewItem類是一個JAVA Bean類,用於存儲側邊欄的listview的每個item,具體代碼如下,包含一張圖片和一個字符串。
/**側滑欄ListView的item*/
public class DrawerLayoutListViewItem {
private int item_picture;//item圖片
private String item_title;//item標題
public DrawerLayoutListViewItem(int item_picture, String item_title) {
this.item_picture = item_picture;
this.item_title = item_title;
}
public int getItem_picture() {
return item_picture;
}
public void setItem_picture(int item_picture) {
this.item_picture = item_picture;
}
public String getItem_title() {
return item_title;
}
public void setItem_title(String item_title) {
this.item_title = item_title;
}
}
DrawerLayoutListViewAdapter類是用於將ArrayList中的數據適配到listview的每個item裏面去的。
每次有子項滑動到屏幕內時就會調用getView方法。爲了充分利用緩存,會首先判斷convertView是否爲空,不爲空的話就直接複用,往view的控件裏面裝載數據即可;如果爲空的話就需要重新加載控件並存儲到viewholder裏面。
package edu.whut.ruansong.musicplayer.tool;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
import edu.whut.ruansong.musicplayer.R;
import edu.whut.ruansong.musicplayer.model.DrawerLayoutListViewItem;
public class DrawerLayoutListViewAdapter extends ArrayAdapter<DrawerLayoutListViewItem> {
private int resourceId;//用來放置佈局文件的id
//適配器的構造函數
public DrawerLayoutListViewAdapter(Context context, int textViewResourceId, List<DrawerLayoutListViewItem> objects) {
super(context, textViewResourceId, objects);
resourceId = textViewResourceId;
}
class ViewHolder {
ImageView itemImage;
TextView itemTitle;
}
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
DrawerLayoutListViewItem item = getItem(position); // 獲取當前項的item實例
View view;//子項佈局對象
ViewHolder viewHolder;//內部類對象
if(convertView == null){//第一次加載
view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
viewHolder = new ViewHolder();
viewHolder.itemImage = view.findViewById(R.id.drawer_layout_list_item_image);
viewHolder.itemTitle = view.findViewById(R.id.drawer_layout_list_item_title);
}else{//不是第一次,即佈局文件已經加載,可以利用
view = convertView;
viewHolder = (ViewHolder) view.getTag();
}
if(item != null && viewHolder!= null){
viewHolder.itemImage.setImageResource(item.getItem_picture());
viewHolder.itemTitle.setText(item.getItem_title());
}
return view;
}
}
側邊欄效果如圖3:
4.搜索圖標的實現
搜索圖標不是在佈局文件中寫出來的,是通過menu文件配合代碼實現的。
在res目錄下新建menu文件夾,新建xml文件,命名爲menu_xxxxx.xml(這裏我命名爲menu_display.xml)。
app:showAsAction="always"表示toolbar有沒有空間都會要求顯示搜索圖標。
item標籤是可以多實現幾個的,多了以後可能會出現豎狀的3個點,點擊以後會出現詳細的選項。
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/display_toolbar_menu_search"
android:title="@string/search"
android:icon="@drawable/search"
app:showAsAction="always"/>
</menu>
然後在DisplayActivity(主界面activity)中重寫父類的兩個方法,代碼如下:
/**
* toolbar的menu加載
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_display, menu);
return true;
}
/**
* toolbar的menu點擊事件
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.display_toolbar_menu_search://toolbar上的搜索按鈕
Intent intent_jump_toolbar_search =
new Intent(DisplayActivity.this, SearchDetailActivity.class);
startActivity(intent_jump_toolbar_search);
break;
default:
break;
}
return true;
}
這裏搜索圖標的點擊事件是跳轉到搜索界面(SearchDetailActivity)去。
5.歷史播放記錄控件的實現
歷史播放記錄控件是一個單獨的佈局文件實現的。用垂直的線性佈局包含了一個文本框和一個listview控件,背景採用圓角卡片式效果。
然後在DisplayActivity的佈局文件中採用include的方式引入歷史播放記錄控件。
<include layout="@layout/my_history_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/dp_10"
android:layout_above="@+id/play_bar_bottom"/>
圓角卡片式的實現採用新建xml文件,寫shape標籤的形式來實現,具體代碼如下。
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- 描邊 -->
<stroke
android:width="1dp"
android:color="@color/black_color" />
<!-- 漸變 -->
<gradient
android:startColor="#D5CFCF"
android:endColor="#D5CFCF"/>
<!-- 圓角角度 -->
<corners
android:radius="10dp" />
</shape>
6.播放進度條
採用ProgressBa控件實現,在後臺服務service中定時向主界面發送廣播更新進度條的進度。
style設置進度條爲水平方向,可選垂直方向
在styles.xml文件中colorAccent定義了進度條的默認顏色,如下語句:
@color/colorAccent
<ProgressBar
android:id="@+id/progressBar_activity_display"
android:layout_width="match_parent"
android:layout_height="5dp"
android:layout_above="@+id/play_bar_bottom"
android:max="100"
android:progress="0"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:background="@color/gray_color"/>
7.底部播放狀態控制條
具體實現可以參閱代碼activity_display.xml,只是單純的控件的堆疊。
以上是主界面的界面的實現,下一篇計劃分析本應用的播放邏輯的控制方法。
求贊,謝謝