前面讲了下面的菜单布局与中间的fragmentLayout的布局与实现,今天就写了顶部title的布局以及去搜索本地sd卡里的视频。
一、顶部布局实现
效果图如下:
1、分析下:
a、这个顶部布局是个LinearLayout布局
b、左侧这个321影音是个ImageView,然后这个搜索框是一个TextView,右侧的游戏图标是个相对布局,里面是一个textview和一个Image构成的点,最右侧的那个记录是一个Imageview
c、最主要的是中间的这个搜索框,为什么是一个textview呢,这个组件的drawableleft是一个搜索图标,背景是一个矩形,然后这个textview还可以点击,就实现了这个搜索框的设计,详细见代码。
2、activity_main.xml里,把顶部的这个布局作为一个外部布局文件,然后引入到这里。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <!-- 标题栏--> <include layout="@layout/activity_titlebar"/> <!--frameLayout --> <FrameLayout android:background="#22000000" android:id="@+id/fl_main_content" android:layout_weight="1" android:layout_width="match_parent" android:layout_height="0dp"/> . . . .
2、activity_titlebar.xml里,最外层是一个LinearLayout,这里显示的是一个TitleBar,是因为我自定义了一个类,继承了LinearLayout,这个类实现了标题栏布局里组件的初始化、点击事件。
<?xml version="1.0" encoding="utf-8"?> <com.yuanlp.mobileplayer.view.TitleBar xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:background="#ff3097fd" android:gravity="center_vertical" android:layout_height="55dp"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_topbanner_logo" android:layout_marginLeft="8dp" /> <TextView android:layout_weight="1" android:layout_marginLeft="5dp" android:drawablePadding="3dp" android:id="@+id/tv_search" android:drawableLeft="@drawable/tv_search_drawable_selector" android:background="@drawable/tv_search_bg_selector" android:textColor="@drawable/ic_tv_search_textcolor_selector" android:clickable="true" android:textSize="14sp" android:text="全网搜索" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <RelativeLayout android:id="@+id/rl_game" android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:id="@+id/tv_game" android:drawableLeft="@drawable/ic_topbanner_game" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <ImageView android:layout_alignRight="@+id/tv_game" android:background="@drawable/dot" android:layout_width="6dp" android:layout_height="6dp"/> </RelativeLayout> <ImageView android:id="@+id/iv_record" android:layout_marginLeft="5dp" android:layout_marginRight="8dp" android:background="@drawable/ic_topbanner_record" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </com.yuanlp.mobileplayer.view.TitleBar>
3、TitleBar 用于对title布局里组件的实例化与点击事件
package com.yuanlp.mobileplayer.view;
import android.content.Context;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.Toast;
import com.yuanlp.mobileplayer.R;
/**
* Created by 原立鹏 on 2017/7/14.
* 自定义标题栏类
*/
public class TitleBar extends LinearLayout implements View.OnClickListener {
private View tv_search; //输入框的ID对应的控件
private View rl_ganme;
private View iv_record;
private Context context;
/**
* 在代码中实例化该类的时候,使用
* @param context
*/
public TitleBar(Context context) {
this(context,null);
}
/**
* 在布局文件使用时,Android系统通过这个构造方法实例化该类
* @param context
* @param attrs
*/
public TitleBar(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
/**
* 当需要设置样式的时候,可以使用该方法
* @param context
* @param attrs
* @param defStyleAttr
*/
public TitleBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context=context;
}
/**
* 当布局文件加载完成后,回调这个方法
*/
@Override
protected void onFinishInflate() {
super.onFinishInflate();
//得到子控件实例
tv_search=getChildAt(1);
rl_ganme=getChildAt(2);
iv_record=getChildAt(3);
//设置点击事件
tv_search.setOnClickListener(this);
rl_ganme.setOnClickListener(this);
iv_record.setOnClickListener(this);
}
/**
* Called when a view has been clicked.
*
* @param v The view that was clicked.
*/
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.tv_search:
Toast.makeText(context,"点击了搜索",Toast.LENGTH_SHORT).show();
break;
case R.id.rl_game:
Toast.makeText(context,"点击了游戏",Toast.LENGTH_SHORT).show();
break;
case R.id.iv_record:
Toast.makeText(context,"点击了播放历史",Toast.LENGTH_SHORT).show();
break;
}
}
}至此,整个主界面的布局完成,后面的就是完善细节。
二、搜索本地视频
搜索本地视频,有2种办法:
第一种是笨方法,检索SD卡里后缀名,获取视频,
第二种:Android系统会在SD卡插拔后,自动通过Media provder来检索视频,然后存储,然后通过ContentProvder来对外公布这些视频信息。
在这里主要使用第二种办法。
1、定义展现视频列表的布局,在这里通过listview来展现视频列表,有一个progressbar,在加载数据时显示,加载完成后隐藏;一个textview,当没有视频时,显示提示信息,有视频时,不显示。
activity_pager.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/listview" android:layout_width="match_parent" android:layout_height="match_parent"></ListView> <TextView android:visibility="gone" android:textSize="18sp" android:textColor="#000000" android:id="@+id/tv_nomedia" android:text="没有发现视频" android:layout_centerInParent="true" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <ProgressBar android:layout_centerInParent="true" android:id="@+id/pb_loading" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </RelativeLayout>
2、重写VideoPager
在初始化该类时,加载上面的这个布局,并实例化各个组件,然后在初始化数据时,去获取SD卡数据。这里加载数据,要在子线程中去写,不能卸载UI线程中,防止出现ANR错误。通过Handler来实现。
package com.yuanlp.mobileplayer.pager;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.view.View;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.yuanlp.mobileplayer.R;
import com.yuanlp.mobileplayer.base.BasePager;
import com.yuanlp.mobileplayer.bean.MediaItem;
import com.yuanlp.mobileplayer.utils.LogUtil;
import java.util.ArrayList;
import java.util.List;
/**
* Created by 原立鹏 on 2017/7/13.
* 本地视频的页面
*/
public class VideoPager extends BasePager {
private ListView listview;
private TextView nomedia;
private ProgressBar pb_loding;
//保存所有的媒体信息的集合
private List<MediaItem> mediaList;
public VideoPager(Context context) {
super(context);
}
private Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (mediaList!=null&&mediaList.size()>0){
//有数据
//设置适配器
}else{
//没有数据
//文本显示
}
//progressbar隐藏
}
};
/**
* 强制子类实现特定的效果
*
* @return
*/
@Override
public View initView() {
LogUtil.e("本地视频被初始化了");
View view=View.inflate(context, R.layout.video_pager,null);
listview= (ListView) view.findViewById(R.id.listview);
nomedia= (TextView) view.findViewById(R.id.tv_nomedia);
pb_loding= (ProgressBar) view.findViewById(R.id.pb_loading);
return view;
}
@Override
public void initData() {
super.initData();
LogUtil.e("本地视频页面的数据被初始化了");
//加载本地数据
getDataFromLocal();
}
/**
* 从本地sd卡获取数据,有2中办法
* 1、遍历sd卡,根据后缀名
* 2、从内容提供者中获取,系统有自己会去扫描所有media信息。
* 3/6.0后的系统,需要加上动态权限
*/
private void getDataFromLocal() {
mediaList=new ArrayList<>();
new Thread(){
@Override
public void run() {
super.run();
//根据上下文,去获取内容解析者
ContentResolver resolver = context.getContentResolver();
Uri uri= MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
String[] objs={
MediaStore.Video.Media.DISPLAY_NAME, //视频文件名称
MediaStore.Video.Media.DURATION, //视频时长
MediaStore.Video.Media.SIZE, //文件大小
MediaStore.Video.Media.DATA, //视频的绝对地址
MediaStore.Video.Media.ARTIST, //歌曲的演唱者,艺术家(音频可能会有该字段)
};
Cursor cursor = resolver.query(uri, objs, null, null, null);
if (cursor!=null){
while(cursor.moveToNext()){
MediaItem item=new MediaItem();
String name=cursor.getString(0); //名称
item.setName(name);
long duration=cursor.getLong(1); //时长
item.setDuration(duration);
long size=cursor.getLong(2); //视频大小
item.setSize(size);
String data=cursor.getString(3); //视频的绝对地址
item.setData(data);
String artist=cursor.getString(4); //艺术家
item.setArtist(artist);
mediaList.add(item); //把每个item数据放到集合中
}
cursor.close();
}
//发消息,提示加载完media
handler.sendEmptyMessage(0);
}
}.start();
}
}3、音视频的实体类,MediItem,主要是音视频的一些属性形成的类
package com.yuanlp.mobileplayer.bean;
/**
* Created by 原立鹏 on 2017/7/14.
* 代表一个视频和音频
*/
public class MediaItem {
private String name;
private long duration;
private long size;
private String data;
private String artist;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getDuration() {
return duration;
}
public void setDuration(long duration) {
this.duration = duration;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public String getArtist() {
return artist;
}
public void setArtist(String artist) {
this.artist = artist;
}
@Override
public String toString() {
return "MediaItem{" +
"name=‘" + name + ‘\‘‘ +
", duration=" + duration +
", size=" + size +
", data=‘" + data + ‘\‘‘ +
", artist=‘" + artist + ‘\‘‘ +
‘}‘;
}
}今天主要的地方就是在于标题栏布局中的搜索框那里,还有就是获取本地SD卡的数据方法。
本文出自 “YuanGuShi” 博客,请务必保留此出处http://cm0425.blog.51cto.com/10819451/1947740
原文地址:http://cm0425.blog.51cto.com/10819451/1947740