開發平臺 : eclipse , ubuntu ,android ?sdk 4.0+
### 1.背景
? ?主頁的設計從上往下依次是滾動廣告(ViewFlipper ),分類信息( GridView ),熱門榜單( ListView ),整個界面可以滑動,通過ScrollView 包裹,使得整個頁面可滑動。
? ?界面展示 :?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
? ? ?后發現遇到的問題 , ListView 滑動和 ScrollView 沖突,后整個布局進行了修改,下面的熱門榜單是通過 Fragment 實現,在啟動的時候進行數據加載。但是有一個問題,如果上面分類信息(GridView)沒有實現的話,下面Fragment加載完成并適配好數據的時候,重新定義Fragment 所要適配的布局的高度,進行重新定義,將會蹦到該Fragment上,故在完成GridView的時候,就不在‘蹦’了,如上圖所示,效果還不錯。
### 2.廣告欄實現(ViewFlipper )
? ?ViewFlipper 的實現 ,布局是自定義布局實現的,包括背景,透明層,左右的文字顯示;
? (1)ViewFlipper 內容布局實現
~~~
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="200dp" >
<ImageView
android:id="@+id/iv_list_item_flipper"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
android:src="@drawable/moren_big" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_alignParentBottom="true"
android:background="@color/app_color_borwn" >
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center|left"
android:layout_marginLeft="20dp"
android:text="@string/tv_main_xindie"
android:textColor="@color/text_color_whrit" />
</FrameLayout>
<TextView
android:id="@+id/tv_list_item_num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_margin="10dp"
android:text="@string/list_item_flipper_tv"
android:textColor="@color/text_color_whrit" />
</RelativeLayout>
~~~
? ?(2)布局實現
~~~
<ViewFlipper
android:id="@+id/main_view_flipper"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_marginTop="10dp" >
</ViewFlipper>
~~~
? ?(3)初始化VIewFlipper實現
~~~
private void initViewFlipper() {
main_view_flipper.setInAnimation(this, R.drawable.main_fliper_in);
main_view_flipper.setOutAnimation(this, R.drawable.main_fliper_out);
main_view_flipper.setOnTouchListener(new viewFlipperListener());
for (int i = 0; i < 4; i++) {
flipperView = LayoutInflater.from(this).inflate(
R.layout.list_item_main_flipper, main_scroll_view, false);
flipperTv = (TextView) flipperView
.findViewById(R.id.tv_list_item_num);
flipperIv = (ImageView) flipperView
.findViewById(R.id.iv_list_item_flipper);
flipperIv.setTag(VolleyHttpPath.RANDOM_IMAGE_URL);
flipperTv.setText((i + 1) + "/4");
~~~
~~~
//加載網絡圖片實現Volley 框架實現
imageListener = ImageLoader.getImageListener(flipperIv,
R.drawable.moren, R.drawable.moren_big);
main_view_flipper.addView(flipperView);
VolleyHttpRequest.Image_Loader(VolleyHttpPath.RANDOM_IMAGE_URL
+ "?" + i, imageListener);
}
main_view_flipper.setFlipInterval(7000);
main_view_flipper.startFlipping();
}
~~~
? ?(4)兩個動畫
? ? ? ? ---fade in
~~~
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<translate
android:duration="800"
android:fromXDelta="-100%p"
android:toXDelta="0" />
</set>
~~~
? ? ? ?---fade out?
~~~
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<translate
android:duration="800"
android:fromXDelta="0"
android:toXDelta="100%p" />
</set>
~~~
? ? (5)手勢控制
~~~
/**
* ViewFlipper 手勢控制
*
*/
private class viewFlipperListener implements OnTouchListener {
private int start = 0;
@Override
public boolean onTouch(View v, MotionEvent event) {
gestureDetector.onTouchEvent(event);
return true;
}
}
/**
* 手勢判斷
*
*/
private class gestureDetectorListener extends SimpleOnGestureListener {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
if (e1.getX() - e2.getX() < 1000) {
main_view_flipper.showPrevious();
}
return true;
}
}
~~~
### 3. 分類信息 (GridView)
? ? 靜態數據,非網絡請求,使用了最簡單的數據適配,并添加點擊事件;
? ?(1) 布局實現
? ? ? ? ? ? 1)GridView 布局
~~~
<GridView
android:id="@+id/main_gridview"
android:layout_width="356dp"
android:layout_height="match_parent"
android:layout_marginTop="2dp"
android:gravity="center"
android:horizontalSpacing="0dp"
android:numColumns="4"
android:scrollbars="none"
android:verticalSpacing="0dp" >
</GridView>
~~~
? ? ? ? ? ? ? ? 2)Item布局
~~~
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_margin="1dp"
android:background="@color/text_color_whrit" >
<ImageView
android:id="@+id/iv_item_main_gird"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_centerInParent="true"
android:src="@drawable/logo" />
<TextView
android:id="@+id/tv_item_main_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="center"
android:text="@string/list_item_grid_tv"
android:textColor="@color/text_color_main" />
</RelativeLayout>
~~~
? ? (2)Adapter實現
~~~
public class MusicGridAdapter extends BaseAdapter {
/**
* 主界面 分類信息,適配Adapter
*/
private SparseArray<String> gridItems;
private Context context;
private ViewHolder holder = null;
private int[] ids = { R.drawable.mingyao, R.drawable.xiaoliang,
R.drawable.china, R.drawable.oumei, R.drawable.hongkang,
R.drawable.hanguo, R.drawable.riben, R.drawable.yaogun };
public void setGridItems(SparseArray<String> gridItems) {
this.gridItems = gridItems;
}
public void setContext(Context context) {
this.context = context;
}
@Override
public int getCount() {
return gridItems.size() > 0 ? gridItems.size() : 0;
}
@Override
public String getItem(int position) {
// TODO Auto-generated method stub
return gridItems.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(
R.layout.list_item_main_gridview, parent, false);
holder = new ViewHolder(convertView);
}
holder.tv_item_main_grid.setText(gridItems.get(position) + "");
holder.iv_item_main_gird.setImageResource(ids[position]);
return convertView;
}
private class ViewHolder {
/**
* ViewHolder
*/
public ImageView iv_item_main_gird;
public TextView tv_item_main_grid;
public ViewHolder(View convertView) {
iv_item_main_gird = (ImageView) convertView
.findViewById(R.id.iv_item_main_gird);
tv_item_main_grid = (TextView) convertView
.findViewById(R.id.tv_item_main_grid);
}
}
}
~~~
? ? ? (3)基本業務實現
~~~
/**
* 初始化 數據
*/
private void initData() {
gridItems.put(0, getString(R.string.music_fenlei_mingyao));
gridItems.put(1, getString(R.string.msuic_fenlei_xiaoliang));
gridItems.put(2, getString(R.string.music_fenlei_china));
gridItems.put(3, getString(R.string.music_fenlei_oumei));
gridItems.put(4, getString(R.string.music_fenlei_hangkang));
gridItems.put(5, getString(R.string.music_fenlei_hanguo));
gridItems.put(6, getString(R.string.music_fenlei_riben));
gridItems.put(7, getString(R.string.music_fenlei_yaogun));
getFenlei();
}
public void getFenlei() {
maps.put(getString(R.string.music_fenlei_mingyao), 18);
maps.put(getString(R.string.msuic_fenlei_xiaoliang), 23);
maps.put(getString(R.string.music_fenlei_china), 5);
maps.put(getString(R.string.music_fenlei_oumei), 3);
maps.put(getString(R.string.music_fenlei_hangkang), 6);
maps.put(getString(R.string.music_fenlei_hanguo), 16);
maps.put(getString(R.string.music_fenlei_riben), 17);
maps.put(getString(R.string.music_fenlei_yaogun), 19);
// 熱歌 26
}
~~~
~~~
// GridView初始化分類信息
MusicGridAdapter musicGridAdapter = new MusicGridAdapter();
musicGridAdapter.setContext(this);
musicGridAdapter.setGridItems(gridItems);
main_gridview.setAdapter(musicGridAdapter);
main_gridview.setOnItemClickListener(new main_gridviewListener());
~~~
? ? (4)點擊監聽事件
~~~
/**
* GirdView點擊事件
*/
private class main_gridviewListener implements OnItemClickListener {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
// showToast("點擊了鄉村 " + maps.get(gridItems.get(position)));
Intent intent = new Intent(MainActivity.this,
MusicListActivity.class);
intent.putExtra("musictype", maps.get(gridItems.get(position)));
startActivity(intent);
}
}
~~~
### 4.熱門榜單實現
? ?使用Fragment 實現 (非v4 包下的),動態的添加到布局中;
? ?實現思路:在MainActivity.xml 給 Fragment一個空白的布局,等待Fragment的填充;
? (1)布局實現
? ? ? --- mainactivity.xml ?中給fragment 預留的布局
~~~
<RelativeLayout
android:id="@+id/main_listview_fragement"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp" />
~~~
?
? ? ? ---- ?fragment.xml 布局實現
~~~
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ListView
android:id="@+id/main_list_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
</RelativeLayout>
~~~
? ? ---- list_item.xml
~~~
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:background="@color/text_color_whrit"
android:layout_height="70dp" >
<TextView
android:id="@+id/list_item_play"
android:layout_width="30dp"
android:layout_height="50dp"
android:layout_alignParentLeft="true"
android:layout_centerInParent="true"
android:layout_margin="10dp"
android:gravity="center"
android:textColor="@color/app_color"
android:text="@string/main_item_num" />
<TextView
android:id="@+id/tv_item_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="18dp"
android:layout_toRightOf="@+id/list_item_play"
android:maxLines="2"
android:text="@string/list_item_song_name"
android:textColor="@color/text_color_black"
android:textSize="12sp" />
<TextView
android:id="@+id/tv_item_singer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_item_name"
android:layout_toRightOf="@+id/list_item_play"
android:text="@string/list_item_singer_name"
android:textColor="@color/text_color_main"
android:textSize="12sp" />
</RelativeLayout>
~~~
?
? ?(2)Fragment實現
~~~
package cn.labelnet.fragment;
import java.util.ArrayList;
import java.util.List;
import cn.labelnet.adapter.MusicListAdapter;
import cn.labelnet.event.MainToFragmentRefrsh;
import cn.labelnet.maskmusic.R;
import cn.labelnet.model.MusicModel;
import cn.labelnet.net.MusicAsync;
import cn.labelnet.net.MusicAsyncHandler;
import cn.labelnet.net.MusicRequest;
import android.annotation.SuppressLint;
import android.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;
public class MainListViewFragment extends Fragment implements MusicAsync {
/**
* 熱歌榜單實現
* MainActivity界面內容填充
*/
// 數據請求
private MusicRequest musicRequest = null;
private MusicAsyncHandler musicHandler = null;
// listview
private ListView main_list_view;
// adapter
private MusicListAdapter musicAdapter;
private List<MusicModel> mmsList = new ArrayList<MusicModel>();
// 接口 : 給 Main傳遞參數
private MainToFragmentRefrsh mainToFragmentRefrsh;
// 給Fragment 添加此事件
public void setMainToFragmentRefrsh(
MainToFragmentRefrsh mainToFragmentRefrsh) {
this.mainToFragmentRefrsh = mainToFragmentRefrsh;
}
public android.view.View onCreateView(android.view.LayoutInflater inflater,
android.view.ViewGroup container,
android.os.Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main_listview_layout,
container, false);
return view;
};
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// 初始化數據
initData();
// 初始化View
initView(view);
// 數據請求
musicRequest.requestStringData(5);
}
/**
* 初始化View
*
* @param view
*/
private void initView(View view) {
main_list_view = (ListView) view.findViewById(R.id.main_list_view);
musicAdapter = new MusicListAdapter(mmsList, getActivity());
main_list_view.setAdapter(musicAdapter);
main_list_view.setOnItemClickListener(new Main_list_viewListener());
}
/**
* 初始化數據請求
*/
private void initData() {
musicHandler = new MusicAsyncHandler();
musicHandler.setMAsync(this);
musicRequest = new MusicRequest();
musicRequest.setMusicAsyncHandler(musicHandler);
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
if(isVisibleToUser){
musicRequest.requestStringData(5);
}
}
@Override
public void onSuccess(List<MusicModel> mms) {
// 給MainActivity返回size
mainToFragmentRefrsh.changeFragmentHeight(mms.size());
mainToFragmentRefrsh.getMusicModelList(mms);
// 請求成功
// String name = mms.get(1).getSingername();
// showToast(name);
// Log.i("MaskMusic", name);
mmsList.addAll(mms);
musicAdapter.notifyDataSetChanged();
}
@Override
public void onFail(String msg) {
// 請求失敗
showToast(msg);
mainToFragmentRefrsh.onFailListener();
}
/**
* Toast
*
* @param msg
* 消息
*/
private void showToast(String msg) {
Toast.makeText(getActivity(), msg, Toast.LENGTH_SHORT).show();
}
// listview點擊事件
private class Main_list_viewListener implements OnItemClickListener {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
mainToFragmentRefrsh.onListviewOnItemClickListener(position);
}
}
}
~~~
? ? (3)Fragment 中的List 適配器實現
~~~
package cn.labelnet.adapter;
import java.util.List;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import cn.labelnet.maskmusic.R;
import cn.labelnet.model.MusicModel;
public class MusicListAdapter extends BaseAdapter {
/**
* 主頁 listview 音樂列表
* 在MainListViewFragment中實現,實現初始化界面適配
*/
private List<MusicModel> list;
private Context context;
private ViewHolder holder = null;
public MusicListAdapter(List<MusicModel> list, Context content) {
this.list = list;
this.context = content;
}
@Override
public int getCount() {
return list.size() > 0 ? list.size() : 0;
}
@Override
public MusicModel getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(
R.layout.list_item_main_layout, parent, false);
holder = new ViewHolder(convertView);
}
MusicModel musicModel = list.get(position);
String songName = musicModel.getSongname() != null ? musicModel
.getSongname() : "什么東東";
holder.tv_item_name.setText(songName);
String singerName = musicModel.getSingername() != null ? musicModel
.getSingername() : "未知";
position += 1;
String num = position >= 10 ? (position + "") : ("0" + position);
holder.list_item_play.setText(num);
holder.tv_item_singer.setText(singerName);
return convertView;
}
class ViewHolder {
public TextView tv_item_name;
public TextView tv_item_singer, list_item_play;
public ViewHolder(View convertView) {
tv_item_name = (TextView) convertView
.findViewById(R.id.tv_item_name);
tv_item_singer = (TextView) convertView
.findViewById(R.id.tv_item_singer);
list_item_play = (TextView) convertView
.findViewById(R.id.list_item_play);
}
}
}
~~~
? ? (4)Fragment 回調事件 (重點)
? ? ? ? ? ? 回調圖:
? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? 作用:1)當網絡請求成功后,總的條數,從而改變mainactivity.xml中需要填充布局的高度;
? ? ? ? ? ? ? ? ? ? ? ?2)回調出所有的數據 models,進行初始化 Service 和通知欄,消除進度條;
? ? ? ? ? ? ? ? ? ? ? ?3)點擊實現回調,傳遞item的poistion ,在MainActivity中通過廣播通知Service播放這個音樂;
? ? ? ? ? ? ? ? ? ? ? ?4)數據請求失敗調用,提示和消除進度條;
~~~
public interface MainToFragmentRefrsh {
/**
* 傳條數,改變布局高度
*
* @param size
*/
void changeFragmentHeight(int size);
/**
* 得到音樂列表
*
* @param models
*/
void getMusicModelList(List<MusicModel> models);
/**
* ListView點擊事件
*
* @param postion
*/
void onListviewOnItemClickListener(int postion);
/**
* 失敗的回調
*/
void onFailListener();
}
~~~
? ? ? (5)改變Fragment填充到的布局高度
? ? ? ? ? ? ? ? 1)工具類 : 像素px和dp的轉化
~~~
public class ViewUtil {
/**
* dp轉px
* @param context
* @param dpValue
* @return
*/
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/**
* px轉dp
* @param context
* @param pxValue
* @return
*/
public static int px2dip(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
}
~~~
? ? ? ? ? ? 2)實現動態改變布局高度
~~~
/**
* 作用 : 從 Fragment拿過來 總長度,后 設置 Fragment 所在布局的總高度
*/
@Override
public void changeFragmentHeight(int size) {
// 給listView 設置 高度
main_listview_parames.height = ViewUtil.px2dip(this,
ViewUtil.dip2px(this, 70) * size);
main_listview_fragement.setLayoutParams(main_listview_parames);
}
~~~
### 5.總結
? ?通過主頁的實現,可以通過fragment實現復雜的頁面布局(這個布局實現單獨的網絡請求與數據適配),這是目前我可以想到的并可以實現的;在此應用中請求圖片使用了Volley 網絡請求框架,使用的是自己進行[二次封裝](http://blog.csdn.net/LABLENET/article/details/47859613)的。在此之前有人說,可能發生內存泄露問題,經過使用,并沒有發生內存泄露問題,請放心使用。
?*使用地址 :?[http://blog.csdn.net/LABLENET/article/details/47859613](http://blog.csdn.net/LABLENET/article/details/47859613)*
? 下篇將進行Service 的實現,在Service 中實現 進行音樂的控制實現;
- 前言
- Android實戰 - 音心音樂播放器 (開啟篇)
- Android實戰 - 音心音樂播發器 (主界面實現)
- Android實戰 - 音心播放器 (Music Service 實現)
- Android實戰 - 音心播放器 (通知實現音樂的播放/暫停/下一曲控制)
- Android實戰 - 音心播發器 (MusicService ,Notification, MainActivity 總結)
- Android實戰 - 音心播放器 (MusicActivity-音樂播放頁面界面實現)
- Android實戰 - 音心播放器 (MusciActivity-專輯圖片獲得,基本控制實現)
- Android實戰 - 音心播放器(MusicActivity - 歌詞實現)
- Android實戰 - 音心播放器 (MusicActivity - 倒計時 ,進度條實現)
- Android實戰 - 音心播放器 (MusicActivity ,MusicNotification,MusicService總結)
- Android實戰 - 音心播放器 (MusicListActivity - 分類信息界面實現)
- Android實戰 - 音心播放器 (MusicListActivity - 音樂播放和MainActivity的一個問題)
- Android實戰 - 音心播放器 (啟動頁與社交分享(ShareSDK))
- Android實戰 - 音心播放器 (優化Service退出,按兩下退出應用實現)
- Android實戰 - 音心播放器 (項目總結,應用打包發布)