记录学习Android基础的心得08:常用控件(中级篇)P2

Posted 搬砖工人_0803号

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了记录学习Android基础的心得08:常用控件(中级篇)P2相关的知识,希望对你有一定的参考价值。

三、翻页类视图

1.翻页视图

(1)作用和外观
翻页视图ViewPager允许用户在屏幕上左右滑动来切换显示的页面项,相当于一种横向显示的列表,它的默认外观是一片空白区域,ViewPager装载页面项之后如图:

显然,为了降低资源使用,android只需要预先生成三个页面项(前一个,当前,后一个)就可以了,用户
左右滑动会预览前后的页面项,当滑动一定的距离之后才能切换页面项并触发监听器的回调方法。

(2)使用方法
翻页视图同样使用适配器来生成页面项,使用监听器来监听页面切换事件。
它的常用方法有:
void setAdapter(PagerAdapter adapter):设置适配器adapter,它必须是PagerAdapter的子类。
void setCurrentItem(int item):选择翻页视图当前显示的页面项。
void addOnPageChangeListener(ViewPager.OnPageChangeListener listener):设置翻页视图的页面切换事件的监听器,监听器listener需要实现三个方法:
abstract void onPageScrollStateChanged(int state)
abstract void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
abstract void onPageSelected(int position)
:分别在翻页视图滑动状态发生改变,滑动距离改变(可在此获取用户手指具体的滑动距离)和滑动结束时回调。

翻页适配器PagerAdapter和BaseAdapter的用法类似:继承PagerAdapter的子类需要在构造函数中传入页面项的显示数据,在getCount方法中得到页面项的数目,在instantiateItem方法中生成具体的单个页面项,另外,PagerAdapter还可以使用destroyItem方法来回收页面项资源,使用getPageTitle方法获取指定页面项的标题文字。

翻页标题栏PagerTitleStripPagerTabStrip都通常在布局文件中作为ViewPager的子控件,都可以在翻页视图的上方显示页面项的标题。其中,PagerTitleStrip只有单纯的文本显示功能,无法通过点击标题项进行翻页视图页面的切换,而PagerTabStrip的文本下方有横线的标题项代表当前页面项,点击标题项即可同时切换页面项。通常,由于翻页标题栏这个控件内部自动和绑定的翻页视图进行交互,所以开发者不需要对翻页标题栏进行逻辑控制,就把当做一个文本显示控件,常见的处理是在布局文件或代码中里设置一下它的文本显示的属性。注意,布局文件中翻页视图ViewPager和翻页标题栏的标签名都要要填全路径类名,如androidx.viewpager.widget.ViewPager这样,不过,我们也不会傻乎乎的手打代码,一般输入类名的关键字母,AS会弹出一个备选框帮我们自动补全代码的。

接下来通过一个实例来熟悉一下翻页视图的使用方法:
页面布局如图:

首先,继承翻页适配器PagerAdapter,在子类中中生成具体的页面项:

public class ImagePagerAdapter extends PagerAdapter {
    private Context mContext; // 一个上下文对象
    private ArrayList<ImageView> mViewList = new ArrayList<>();// 图像视图队列
    private ArrayList<SoftwareBean> mSoftwareList;// 工具软件队列

    // 图像翻页适配器的构造函数,传入上下文与工具软件队列
    public ImagePagerAdapter(Context context, ArrayList<SoftwareBean> softwareList) {
        mContext = context;
        mSoftwareList = softwareList;
        // 给每个工具软件分配一个专用的图像视图
        for (int i = 0; i < mSoftwareList.size(); i++) {
            ImageView view = new ImageView(mContext);
            view.setLayoutParams(new LayoutParams(
                    LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
            view.setImageResource(mSoftwareList.get(i).image);
            view.setScaleType(ScaleType.FIT_CENTER);
            // 把一个装配完成的图像视图添加到队列中
            mViewList.add(view);
        }
    }

    // 获取页面项的个数
    public int getCount() {
        return mViewList.size();
    }

    //页面项是否和某个对象关联
    @Override
    public boolean isViewFromObject(View arg0, Object arg1) {
        return arg0 == arg1;
    }

    // 从容器中销毁指定位置的页面
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView(mViewList.get(position));
    }

    // 实例化指定位置的页面项,并将其添加到容器中
    public Object instantiateItem(ViewGroup container, int position) {
        container.addView(mViewList.get(position));
        return mViewList.get(position);
    }

    // 获得指定页面项的标题文本
    public CharSequence getPageTitle(int position) {
        return mSoftwareList.get(position).name;
    }
}

适配器负责具体页面项的管理,然后,Activity页面中有关的逻辑处理如下:

 // 初始化翻页标题栏
    private void initPagerStrip() {
        // 从布局视图中获取名叫pts_tab的翻页标题栏
        PagerTabStrip pts_tab = findViewById(R.id.pts_tab);
        // 设置翻页标题栏的文本大小
        pts_tab.setTextSize(TypedValue.COMPLEX_UNIT_SP, 40);
        // 设置翻页标题栏的文本颜色
        pts_tab.setTextColor(Color.BLUE);
    }

    private ArrayList<SoftwareBean> mSoftwareList = SoftwareBean.getDefaultList();
    // 初始化翻页视图
    private void initViewPager() {
        // 构建一个工具软件图片的翻页适配器
        ImagePagerAdapter adapter = new ImagePagerAdapter(this, mSoftwareList);
        // 从布局视图中获取名叫vp_content的翻页视图
        ViewPager vp_content = findViewById(R.id.vp_content);
        // 给vp_content设置图片翻页适配器
        vp_content.setAdapter(adapter);
        // 设置vp_content默认显示第一个页面
        vp_content.setCurrentItem(0);
        // 给vp_content添加页面变化监听器
        vp_content.addOnPageChangeListener(listener);
    }

    private ViewPager.OnPageChangeListener listener = new ViewPager.OnPageChangeListener() {
        // 翻页状态改变时触发。arg0取值说明为:0表示静止,1表示正在滑动,2表示滑动完毕
        // 在翻页过程中,状态值变化依次为:正在滑动→滑动完毕→静止
        public void onPageScrollStateChanged(int arg0) {}

        // 在翻页过程中触发。该方法的三个参数取值说明为 :第一个参数表示当前页面的序号
        // 第二个参数表示当前页面偏移的百分比,取值为0到1;第三个参数表示当前页面的偏移距离
        public void onPageScrolled(int arg0, float arg1, int arg2) {}

        // 在翻页结束后触发。arg0表示当前滑到了哪一个页面
        public void onPageSelected(int arg0) {
            Toast.makeText(MainActivity.this, "当前页面项:"+mSoftwareList.get(arg0).name, Toast.LENGTH_SHORT).show();
        }
    };

当用户滑动至两个页面项中间时,效果如图:

四、对话框

1.提醒对话框

(1)作用和外观
Android提供了多种对话框,常见的有AlertDialog,ProgressDialog,DataPickerDialog,TimerPickerDialog这几类,对话框在页面最前层显示,它会抢占屏幕的焦点,用户无法操作对话框后面的界面。其中提醒对话框AlertDialog的扩展性是最大的,它也是其他对话框的父类,一个提醒对话框的外观如图,它分为4个区域:图标区,标题区,内容区,按钮区:

(2)使用方法
AlertDialog.Builder是提醒对话框的构造类,通过构造类可以最大程度的自定义一个具有特色的对话框,它的常用方法有:
AlertDialog.Builder setIcon(Drawable icon)
AlertDialog.Builder setIcon(int iconId)
:设置图标区使用的图形,iconId代表图形资源的ID。
AlertDialog.Builder setTitle(CharSequence title)
AlertDialog.Builder setTitle(int titleId)
:使用字符串或给定的资源ID设置标题区的文本。
AlertDialog.Builder setMessage(int messageId)
AlertDialog.Builder setMessage(CharSequence message)
:设置要对话框内容区要显示的的文本消息。
AlertDialog.Builder setPositiveButton(CharSequence text, DialogInterface.OnClickListener listener)
AlertDialog.Builder setNegativeButton(CharSequence text, DialogInterface.OnClickListener listener)
AlertDialog.Builder setNeutralButton(CharSequence text, DialogInterface.OnClickListener listener)
:创建“确定”,“取消”,“中性”按钮并设置按钮监听器,注意,不显式调用这些方法则表示不创建这些按钮。
AlertDialog create():使用提供给此构建器的参数创建一个 AlertDialog 。
AlertDialog.Builder setCancelable(boolean cancelable):设置点击对话框范围之外的屏幕时,对话框是否可以消失,默认是true,开发者如果要求用户必须做出选择,则设置为false。
AlertDialog show():使用提供给此构建器的参数创建一个 AlertDialog ,并立即显示该对话框。

以上都是设置对话框内容的常规方法,提醒对话框还支持以下方法来自定义对话框的外观:
AlertDialog.Builder setCustomTitle(View customTitleView):使用自定义视图 customTitleView设置标题区。
AlertDialog.Builder setView(int layoutResId)
AlertDialog.Builder setView(View view)
:将对话框的内容区设置为自定义视图。
AlertDialog.Builder setAdapter(ListAdapter adapter, DialogInterface.OnClickListener listener)
AlertDialog.Builder setItems(CharSequence[] items, DialogInterface.OnClickListener listener)
AlertDialog.Builder setMultiChoiceItems(CharSequence[] items, boolean[] checkedItems, DialogInterface.OnMultiChoiceClickListener listener)
AlertDialog.Builder setSingleChoiceItems(CharSequence[] items, int checkedItem, DialogInterface.OnClickListener listener)
:对话框的内容区使用列表的方式来显示数据。
如此,在指定Activity页面显示一个提醒对话框的流程如下:
①首先创建一个AlertDialog.Builder的实例对象。
②然后调用它的setXXX方法来设置对话框四个不同区域的显示内容。
③最后调用它的create方法来生成一个AlertDialog的实例对象,调用AlertDialog对象的show方法即可显示对话框了,或者直接使用AlertDialog.Builder对象的show方法来代替这两句代码。

那么举个例子来熟悉自定义对话框的内容区,比如把内容区设置为列表的形式代码如下:

    //获取内容区的数据来源
    ArrayList<SoftwareBean> mSoftwareList = SoftwareBean.getDefaultList();
    SoftwareAdapter adapter = new SoftwareAdapter(MainActivity.this,mSoftwareList);
    private void initAlertDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        //设置对话框图标区
        builder.setIcon(R.mipmap.ic_launcher)
                //设置对话框按钮区,暂不处理按钮事件
                .setPositiveButton("确定按钮",null)
                .setNegativeButton("取消按钮",null)
                .setNeutralButton("中间按钮",null)
                //设置标题区
                .setTitle("标题")
                //设置内容区
                .setAdapter(adapter, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        String desc = String.format("您点击了第%d个工具软件,它的名字是%s", which + 1,
                                mSoftwareList.get(which).name);
                        Toast.makeText(MainActivity.this, desc, Toast.LENGTH_LONG).show();
                    }
                })
               .setCancelable(false);//必须与对话框交互才能让对话框消失
        AlertDialog dialog =builder.create();
        dialog.show();
    }

显示效果如图,用户必须与对话框交互(点击按钮或列表项)才能让对话框消失:

2.进度对话框

(1)作用和外观
进度对话框ProgressDialog虽然在手册里被标记为过时的,但它的使用方法确实很简单,而且这个控件也比较实用,比如要求用户在进度完成之前无法对APP界面做任何操作,那么,使用ProgressDialog既可以显示进度又可以抢占屏幕的焦点。ProgressDialog继承自AlertDialog,故它的布局和提醒对话框是一样的,但它额外集成了进度条ProgressBar,于是在内容区就出现了一个进度条控件:

(2)使用方法
ProgressDialog拥有AlertDialog和ProgressBar的所有方法,故这里不再列举,但不同于AlertDialog的使用方式,进度对话框没有构造类来设置对话框内容,它直接通过构造函数来创建对象实例并通过对象实例的各种setXXX方法设置对话框的内容。

那么要实现上图的效果,需要设置的代码如下:

    //初始化进度对话框并显示
    private void initProgressDialog() {
        ProgressDialog dialog = new ProgressDialog(MainActivity.this);
        dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);//条状的进度条
        dialog.setMax(100);
        dialog.setProgress(0);//设置进度条当前进度
        dialog.setIcon(R.mipmap.ic_launcher);
        dialog.setTitle("标题");
        dialog.setMessage("对话框内容");
        dialog.setButton(DialogInterface.BUTTON_NEGATIVE,"取消按钮", (DialogInterface.OnClickListener) null);
        dialog.setButton(DialogInterface.BUTTON_POSITIVE,"确定按钮", (DialogInterface.OnClickListener) null);
        dialog.setButton(DialogInterface.BUTTON_NEUTRAL,"中间按钮", (DialogInterface.OnClickListener) null);
        dialog.setCancelable(false);//必须点击按钮才能让对话框消失
        dialog.show();
    }

3.日期选择对话框

(1)作用和外观
日期选择对话框DatePickerDialog相当于把日期选择器DatePicker以对话框的形式呈现给用户,可以为DatePickerDialog注册监听器来监听当用户选择日期事件,它的外观如图:

当选择好日期后,点击确定会触发监听器的onDateSet方法。
(2)使用方法
DatePickerDialog没有setXXX方法来设置日期内容,如果开发者不追求外观,则可以使用两句代码搞定。只需在构造函数中设置一下当前的日期并设置一个日期选择的监听器,就可以生成一个实例对象了,再调用它的show方法显示出来即可。常用方法如下:
DatePickerDialog(Context context, DatePickerDialog.OnDateSetListener listener, int year, int month, int dayOfMonth):使用context的默认主题作为对话框布局,设置日期选择监听器,设置对话框显示的初始年月日。其中的监听器listener需要实现 abstract void onDateSet(DatePicker view, int year, int month, int dayOfMonth) 方法。
当然也可以动态设置日期和监听器:
void setOnDateSetListener(DatePickerDialog.OnDateSetListener listener):为日期选择对话框设置监听器。
void updateDate(int year, int month, int dayOfMonth):设置当前日期。

4.时间选择对话框

(1)作用和外观
时间选择对话框TimePickerDialog相当于把时间选择器 TimePicker以对话框的形式呈现给用户,不过,它默认不支持秒钟的设置,可以为它设置监听器来监听时间选择事件,它的外观如图:

点击红圈中的图标,可以为TimePickerDialog切换两种不同的外观。选择好时间后,点击确定会触发监听器的onTimeSet方法。
(2)使用方法
它的使用和日期选择对话框一样,开发者如果没有特殊的外观要求的话,可以用两句代码搞定。它的常用方法有:
TimePickerDialog(Context context, TimePickerDialog.OnTimeSetListener listener, int hourOfDay, int minute, boolean is24HourView):使用context的默认主题来创建一个默认外观的时间选择器,注册一个监听器,设置对话框要显示的初始时间,参数is24HourView设置使用24小时或12小时的风格显示。监听器listener需要实现 public void onTimeSet(TimePicker view, int hourOfDay, int minute) 方法。
void updateTime(int hourOfDay, int minuteOfHour):设置当前时间。

日期,时间选择对话框的使用都很简单,实现上图的效果需要的代码段如下:

    Calendar calendar =Calendar.getInstance();//获取日历实例对象
    //初始化日期选择对话框并显示
    private void initDatePickerDialog(){
        DatePickerDialog dialog = new DatePickerDialog(this, new DatePickerDialog.OnDateSetListener() {
            @Override
            public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
                // 获取日期对话框设定的年月份
                String desc = String.format("您选择的日期是%d年%d月%d日",
                        year, month + 1, dayOfMonth);
                Toast.makeText(MainActivity.this, desc, Toast.LENGTH_SHORT).show();;
            }
        },calendar.get(Calendar.YEAR),calendar.get(Calendar.MONTH),calendar.get(Calendar.DAY_OF_MONTH));
        dialog.show();
    }
    //初始化时间选择对话框并显示
    private void initTimePickerDialog(){
        TimePickerDialog dialog =new TimePickerDialog(this, new TimePickerDialog.OnTimeSetListener() {
            @Override
            public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
                // 获取时间对话框设定的时间
                String desc = String.format("您选择的时间是%d时%d分",
                        hourOfDay, minute);
                Toast.makeText(MainActivity.this, desc, Toast.LENGTH_SHORT).show();;
            }
        },calendar.get(Calendar.HOUR),calendar.get(Calendar.MINUTE),true);
        dialog.show();
    }

五、视频视图

(1)作用和外观
视频视图VideoView继承自SurfaceView而且内部集成了MediaPlayer。如同文本视图用于装载并显示文本,图像视图用于装载并显示图像,视频视图是专门用于播放视频的控件,它的默认外观是一片空白的矩形区域。

(2)使用方法
VideoView的方法主要是关于内部集成的MediaPlayer的方法,在前文硬件控制中已经详细总结过了,这里就再简单总结一下VideoView提供给开发者的常用方法:
void setVideoPath(String path)
void setVideoURI(Uri uri, Map<String, String> headers)
void setVideoURI(Uri uri)
:通过不同的参数设置视频来源,可以是手机存储,可以是网络视频。
void addSubtitleSource(InputStream is, MediaFormat format):添加来自输入流is的外部字幕源文件。注意,单个外部字幕源可能包含多个或不支持的音频轨道。
void setOnCompletionListener(MediaPlayer.OnCompletionListener l)
void setOnErrorListener(MediaPlayer.OnErrorListener l)
void setOnInfoListener(MediaPlayer.OnInfoListener l)
void setOnPreparedListener(MediaPlayer.OnPreparedListener l)
:注册播放结束,播放错误,播放过程信息,准备播放的监听器。
void seekTo(int msec):让视频跳到指定时长播放。
int getBufferPercentage()
int getCurrentPosition()
int getDuration()
:获取已经缓冲的时长,当前时长,总时长。
boolean onKeyDown(int keyCode, KeyEvent event)
boolean onTouchEvent(MotionEvent ev)
boolean onTrackballEvent(MotionEvent ev)
:与用户操作按键或屏幕有关的回调函数。
boolean canPause()
boolean isPlaying()
void pause()
void resume()
void start()
void suspend():控制播放状态的几个方法。
void setMediaController(MediaController controller)*:设置与VideoView绑定的媒体控制器MediaController ,如果直接调用此方法,则MediaController会自动附着在VideoView的下方。

媒体控制器MediaController支持基本的播放控制操作,如:显示播放进度,拖动到指定位置播放,暂停/恢复播放,查看播放总时长/已播放时长,快进/快退等,当它与视频视图绑定后,就可以直接和视频视图交互了。这些操作在MediaController通常以相关的图标表示,以此提供给用户直接控制视频视图。
由于MediaController是不可继承的,意味着开发者无法通过继承来改变控制器的外观或者扩展额外功能。MediaController主要是由用户直接操作,开发者也没必要做太多的处理,对于开发者来说,它的常用方法有:
public void setAnchorView(View view) :绑定指定的视频视图。
public void setMediaPlayer(MediaPlayerControl player):指定媒体播放器,效果和方法①一样,故①和②只需调用一个即可。
public boolean isShowing()
public void show()
public void hide()
:与媒体控制器在屏幕上显示/隐藏相关的方法。

使用视频视图来播放视频的步骤如下:
开发者只需在布局中放置一个VideoView控件,在代码中调用setVideoPath方法指定视频文件,再调用setMediaController方法指定媒体控制器,媒体控制器无需在布局文件里添加,使用代码添加就会默认附着在VideoView的下方。最后调用MediaController对象的setAnchorView或setMediaPlayer方法来双向绑定即可。
那么按照以上流程,在布局文件中放置一个ID为vv_content的VideoView,然后很容易写出以下代码:

//初始化视频视图,绑定媒体控制器,播放视频
    private void initVideoView(){
        VideoView vv_content = findViewById(R.id.vv_content); // 获取一个视频视图对象
        // 视频文件的完整路径
        String file_path = "/mnt/sdcard/DCIM/Camera/VID_20211016_161752.mp4";
        // 设置视频视图的视频路径
        vv_content.setVideoPath(file_path);
        // 视频视图请求获得焦点
        vv_content.requestFocus();
        // 创建一个媒体控制条
        MediaController mc_play = new MediaController(this);
        // 给视频视图设置相关联的媒体控制器
        vv_content.setMediaController(mc_play);
        // 给媒体控制器设置相关联的视频视图
        mc_play.setMediaPlayer(vv_content);
        // 视频视图开始播放
        vv_content.start();
    }

随手录制的视频VID_20211016_161752.mp4放在/mnt/sdcard/DCIM/Camera/目录下,例子实现的效果图如下,如果没有在配置文件声明存储权限,就会出现图左1的情况:

六、表面视图和纹理视图

在硬件控制的摄像头小节中,已经使用过了表面视图和纹理视图,但没有深入总结有关方法,在此本小结之前,希望大家还记着Java中的绘图过程和有关的API,这样会更加得心应手的掌握这两个视图。

1.表面视图

(1)作用和外观
表面视图SurfaceView外观和View一样,都是一个空白的矩形区域,开发者通常需要通过继承SurfaceView,然后在这片空白的区域绘制自定义的图形。而不同的是,SurfaceView提供了可以多线程同时绘制的画布。

(2)使用方法
表面视图一般与表面持有者SurfaceHolder结合使用,通过调用SurfaceView的getHolder方法可以获取与之关联的SurfaceHolder对象实例。
SurfaceHolder的常用方法有:
abstract Canvas lockCanvas()
abstract Canvas lockCanvas(Rect dirty)
:锁定与之绑定的表面视图,不允许在该语句调用之后创建,销毁或修改表面视图,同时返回一个表面视图的用于绘制的画布Canvas,参数dirty表示获取表面视图的指定

以上是关于记录学习Android基础的心得08:常用控件(中级篇)P2的主要内容,如果未能解决你的问题,请参考以下文章

android基础篇学习心得

Android Studio应用基础,手把手教你从入门到精通(小白学习)总结1 之 基础介绍 + intent + 常用控件

android 基础UI控件学习总结

简单的学习心得:网易云课堂Android开发第三章自定义控件

Android学习笔记 布局基础

PyQt5窗口设计基础之常用控件类(三)