Android 手机影音 开发过程记录(二)

2024-03-11 14:10

本文主要是介绍Android 手机影音 开发过程记录(二),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前一篇已经将SplashActivity编写好了,这篇主要梳理一下主页面MainActivity。包括:

  1. 实现ViewPager上方的头布局Tab的高亮和缩放动画;
  2. 实现指示线的随手指移动而移动的效果

基类的编写

  • 一般项目开发中,会涉及到很多的Activity和Fragment的使用,而且我们在这些activity或者fragment中操作的方法大致一样:初始化view,初始化data,初始化listener,以及实现一些控件的onClick方法。

  • 所以为了方便,我们将这些方法向上抽取,放到一个BaseActivity以及一个BaseFragment当中去。当需要使用的时候,直接继承我们已经写好的这些基类,这样,不仅少了不少重复代码,而且可读性极大增强,逻辑更加清晰。

public abstract class BaseActivity extends FragmentActivity implements View.OnClickListener{@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);initViews();initData();initListeners();}protected abstract void initViews();protected abstract void initData();protected abstract void initListeners();/**可以处理共同点击事件的按钮(比如像一些项目的TitleBar都有一个返回按钮)*/protected abstract void processClick(View view);@Overridepublic void onClick(View view) {processClick(view);}
}

说明:这里基类继承的是FragmentActivity而不是Activity,主要是考虑到主页面的viewpager嵌套了两个fragment,它的的适配器是继承FragmentPagerAdapter,这是v4包下的,所以主页面需要通过继承FragmentActivity来getSupportFragmentManager得到这个fragmentManager。

这里顺道把BaseFragment的编写也贴上,后面要用到。跟BaseActivity差不多。

public abstract class BaseFragment extends Fragment implements View.OnClickListener {@Overridepublic void onAttach(Activity activity) {super.onAttach(activity);}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {View view = initView(inflater, container, savedInstanceState);return view;}@Overridepublic void onActivityCreated(Bundle savedInstanceState) {super.onActivityCreated(savedInstanceState);initData();initListener();}protected abstract View initView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState);protected abstract void initData();protected abstract void initListener();protected abstract void processClick(View view);@Overridepublic void onClick(View v) {processClick(v);}protected void enterActivity(Class<?> targetClass) {startActivity(new Intent(getActivity(), targetClass));}protected void enterActivity(Class<?> targetClass, Bundle bundle) {Intent intent = new Intent(getActivity(), targetClass);intent.putExtras(bundle);startActivity(intent);}

说明:这里多了enterActivity()的两个重载的方法,是根据该项目需求抽取的。因为该项目中,fragment中加入的是一个listview控件,点击其中的一个item会跳转到一个activity中去,有时带数据,有时不带,为了代码整洁,所以都抽取到BaseFragment中了。

主页面布局以及标题栏Tab高亮&缩放效果

  • 前提:既然是自己定义标题栏,就不能忘了把系统自带的标题栏给去掉。
    在style.xml文件中AppTheme的样式下加入下面代码:
<item name="android:windowNoTitle">true</item>

1. 主页面布局文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@mipmap/base_bg"android:orientation="vertical"><RelativeLayout
        android:layout_width="match_parent"android:layout_height="55dp"android:background="@mipmap/base_titlebar_bg"><LinearLayout
            android:layout_width="match_parent"android:layout_height="match_parent"><TextView
                android:id="@+id/tv_tab_video"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:gravity="center"android:text="视频"android:textColor="@color/indicate_line"android:textSize="18sp" /><TextView
                android:id="@+id/tv_tab_audio"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:gravity="center"android:text="音乐"android:textColor="@color/gray_white"android:textSize="18sp" /></LinearLayout><View
            android:id="@+id/indicate_line"android:layout_width="0dp"android:layout_height="3dp"android:layout_alignParentBottom="true"android:background="@color/indicate_line" /></RelativeLayout><android.support.v4.view.ViewPager
        android:id="@+id/vp"android:layout_width="match_parent"android:layout_height="match_parent"></android.support.v4.view.ViewPager></LinearLayout>

2. 标题栏高亮及缩放:

  • 这里缩放的动画效果是用的属性动画,API_12及以上才有,如果想兼容低版本,可以用 nineoldandroids-2.4.0.jar来实现。
    /*** 高亮显示并且缩放标签标题* @param position viewpager的currentItem的position*/private void highligthAndScaleTabTitle(int position) {tvVideo.setTextColor(position == 0 ? getResources().getColor(R.color.indicate_line): getResources().getColor(R.color.gray_white));tvAudio.setTextColor(position == 1 ? getResources().getColor(R.color.indicate_line): getResources().getColor(R.color.gray_white));tvVideo.animate().scaleX(position == 0 ? 1.2f : 1.0f).scaleY(position == 0 ? 1.2f : 1.0f).setDuration(200);tvAudio.animate().scaleX(position == 0 ? 1.0f : 1.2f).scaleY(position == 0 ? 1.0f : 1.2f).setDuration(200);}

标题栏指示线的随手指移动而移动效果

思考:

  1. 指示线的宽是多少了呢?该项目中是屏幕宽的一半,但能写死吗?万一后来需求改了,标题栏要求添加一个tab呢?很显然,这个指示线不能写死,得根据标签的数量动态去设置,两个标签,宽就是屏幕的1/2,三个标签,宽就是屏幕的1/3。fragment的数量就是标签的数量,因为每一个标签对应一个fragment。
  2. 如何让指示线随手指的滑动而滑动呢?是不是应该这样:viewpager滑动一个页面的距离(即屏幕宽),指示线就应该移动它本身的宽度。在viewpager的onPageScrolled(int position, float positionOffset, int positionOffsetPixels)方法中,参数position是当前fragment的位置,参数positionOffset就是手指滑动距离占屏幕总宽的比率,参数positionOffsetPixels就是滑动的像素值。
  3. 有了滑动比率,指示线的宽,就好办了,拿 lineWidth * positionOffset不就是指示线应该滑动的距离吗。原理就是这么简单,但要注意,指示线在移动的时候,要把原始的位置加上,不然,它会一直在屏幕左边滑动。lineWidth * position + lineWidth * positionOffset。
  4. 偏移亮计算出来了,这里还是用属性动画来实现随手指滑动。通过setDuration(0)来达到效果。

贴张图再次加深对上面文字的理解。
这里写图片描述

计算指示线宽度的代码:

    /*** 计算指示器的宽度*/private void calculateIndicateLineWidth() {Point point = new Point();this.getWindowManager().getDefaultDisplay().getSize(point);int screenWidth = point.x;lineWidth = screenWidth / fragments.size();LogUtils.i("lineWidth = " + lineWidth);indicateLine.getLayoutParams().width = lineWidth;indicateLine.requestLayout();}

指示线随手指滑动的代码:(在监听viewpager的onPageScrolled()的方法里设置)

            @Overridepublic void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
//                LogUtils.i("position = " + position + ",positionOffset = " + positionOffset
//                        + ",positionOffsetPixels = " + positionOffsetPixels);float delatX = lineWidth * (position + positionOffset);LogUtils.i("delatX = " + delatX);indicateLine.animate().translationX(delatX).setDuration(0);}

主页面完整代码

说明:该项目用了xUtils框架中的注解功能,省去大量的 findViewById()操作。

public class MainActivity extends BaseActivity {@ViewInject(R.id.vp)private ViewPager vp;@ViewInject(R.id.tv_tab_video)private TextView tvVideo;@ViewInject(R.id.tv_tab_audio)private TextView tvAudio;@ViewInject(R.id.indicate_line)private View indicateLine;private List<BaseFragment> fragments;private int lineWidth;//指示线的宽度protected void initViews() {setContentView(R.layout.activity_main);ViewUtils.inject(this);}protected void initData() {fragments = new ArrayList<>();fragments.add(new VideoListFragment());fragments.add(new AudioListFragment());calculateIndicateLineWidth();MainUiAdapter adapter = new MainUiAdapter(getSupportFragmentManager(), fragments);vp.setAdapter(adapter);highligthAndScaleTabTitle(0);}protected void initListeners() {tvVideo.setOnClickListener(this);tvAudio.setOnClickListener(this);vp.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {@Overridepublic void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
//                LogUtils.i("position = " + position + ",positionOffset = " + positionOffset
//                        + ",positionOffsetPixels = " + positionOffsetPixels);float delatX = lineWidth * (position + positionOffset);LogUtils.i("delatX = " + delatX);indicateLine.animate().translationX(delatX).setDuration(0);}@Overridepublic void onPageSelected(int position) {highligthAndScaleTabTitle(position);}@Overridepublic void onPageScrollStateChanged(int state) {}});}@Overrideprotected void processClick(View view) {switch (view.getId()) {case R.id.tv_tab_video:vp.setCurrentItem(0);break;case R.id.tv_tab_audio:vp.setCurrentItem(1);break;}}/*** 高亮显示并且缩放标签标题* @param position viewpager的currentItem的position*/private void highligthAndScaleTabTitle(int position) {tvVideo.setTextColor(position == 0 ? getResources().getColor(R.color.indicate_line): getResources().getColor(R.color.gray_white));tvAudio.setTextColor(position == 1 ? getResources().getColor(R.color.indicate_line): getResources().getColor(R.color.gray_white));tvVideo.animate().scaleX(position == 0 ? 1.2f : 1.0f).scaleY(position == 0 ? 1.2f : 1.0f).setDuration(200);tvAudio.animate().scaleX(position == 0 ? 1.0f : 1.2f).scaleY(position == 0 ? 1.0f : 1.2f).setDuration(200);}/*** 计算指示器的宽度*/private void calculateIndicateLineWidth() {Point point = new Point();this.getWindowManager().getDefaultDisplay().getSize(point);int screenWidth = point.x;lineWidth = screenWidth / fragments.size();LogUtils.i("lineWidth = " + lineWidth);indicateLine.getLayoutParams().width = lineWidth;indicateLine.requestLayout();}private long exitTime = 0;@Overridepublic void onBackPressed() {if(System.currentTimeMillis() - exitTime > 2000){ToastUtil.showShort(this, "再按一次退出手机影音");exitTime =System.currentTimeMillis();}else{finish();}}
}

好了,先整理到这里。

这篇关于Android 手机影音 开发过程记录(二)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/798015

相关文章

Python通过模块化开发优化代码的技巧分享

《Python通过模块化开发优化代码的技巧分享》模块化开发就是把代码拆成一个个“零件”,该封装封装,该拆分拆分,下面小编就来和大家简单聊聊python如何用模块化开发进行代码优化吧... 目录什么是模块化开发如何拆分代码改进版:拆分成模块让模块更强大:使用 __init__.py你一定会遇到的问题模www.

Spring Security基于数据库的ABAC属性权限模型实战开发教程

《SpringSecurity基于数据库的ABAC属性权限模型实战开发教程》:本文主要介绍SpringSecurity基于数据库的ABAC属性权限模型实战开发教程,本文给大家介绍的非常详细,对大... 目录1. 前言2. 权限决策依据RBACABAC综合对比3. 数据库表结构说明4. 实战开始5. MyBA

使用Python开发一个简单的本地图片服务器

《使用Python开发一个简单的本地图片服务器》本文介绍了如何结合wxPython构建的图形用户界面GUI和Python内建的Web服务器功能,在本地网络中搭建一个私人的,即开即用的网页相册,文中的示... 目录项目目标核心技术栈代码深度解析完整代码工作流程主要功能与优势潜在改进与思考运行结果总结你是否曾经

Python获取中国节假日数据记录入JSON文件

《Python获取中国节假日数据记录入JSON文件》项目系统内置的日历应用为了提升用户体验,特别设置了在调休日期显示“休”的UI图标功能,那么问题是这些调休数据从哪里来呢?我尝试一种更为智能的方法:P... 目录节假日数据获取存入jsON文件节假日数据读取封装完整代码项目系统内置的日历应用为了提升用户体验,

将Mybatis升级为Mybatis-Plus的详细过程

《将Mybatis升级为Mybatis-Plus的详细过程》本文详细介绍了在若依管理系统(v3.8.8)中将MyBatis升级为MyBatis-Plus的过程,旨在提升开发效率,通过本文,开发者可实现... 目录说明流程增加依赖修改配置文件注释掉MyBATisConfig里面的Bean代码生成使用IDEA生

Android中Dialog的使用详解

《Android中Dialog的使用详解》Dialog(对话框)是Android中常用的UI组件,用于临时显示重要信息或获取用户输入,本文给大家介绍Android中Dialog的使用,感兴趣的朋友一起... 目录android中Dialog的使用详解1. 基本Dialog类型1.1 AlertDialog(

Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

《SpringBoot+MyBatisPlus高效开发实战从入门到进阶优化(推荐)》本文将详细介绍SpringBoot+MyBatisPlus的完整开发流程,并深入剖析分页查询、批量操作、动... 目录Spring Boot + MyBATis Plus 高效开发实战:从入门到进阶优化1. MyBatis

Spring Boot 配置文件之类型、加载顺序与最佳实践记录

《SpringBoot配置文件之类型、加载顺序与最佳实践记录》SpringBoot的配置文件是灵活且强大的工具,通过合理的配置管理,可以让应用开发和部署更加高效,无论是简单的属性配置,还是复杂... 目录Spring Boot 配置文件详解一、Spring Boot 配置文件类型1.1 applicatio

Python基于wxPython和FFmpeg开发一个视频标签工具

《Python基于wxPython和FFmpeg开发一个视频标签工具》在当今数字媒体时代,视频内容的管理和标记变得越来越重要,无论是研究人员需要对实验视频进行时间点标记,还是个人用户希望对家庭视频进行... 目录引言1. 应用概述2. 技术栈分析2.1 核心库和模块2.2 wxpython作为GUI选择的优

C# WinForms存储过程操作数据库的实例讲解

《C#WinForms存储过程操作数据库的实例讲解》:本文主要介绍C#WinForms存储过程操作数据库的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、存储过程基础二、C# 调用流程1. 数据库连接配置2. 执行存储过程(增删改)3. 查询数据三、事务处