前面讲了下面的菜单布局与中间的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卡的数据方法。