Android6.0的phone应用源码分析(3)——phone 拨号UI分析
1.1 原生界面
Phone应用的UI设计直接关系到后面的去来电流程,因此有必要对Phone的UI做一定的介绍。下面是Android6.0的原生拨号界面:
1.2 应用界面
Phone的UI入口可以认为是DialtactsActivity.java的onCreate()。
@Override protected void onCreate(Bundle savedInstanceState) { Trace.beginSection(TAG + " onCreate"); super.onCreate(savedInstanceState); mFirstLaunch = true;//首次launch标志 final Resources resources = getResources(); mActionBarHeight = resources.getDimensionPixelSize(R.dimen.action_bar_height_large);//获取高度 Trace.beginSection(TAG + " setContentView"); setContentView(R.layout.dialtacts_activity);//获得布局文件 Trace.endSection(); getWindow().setBackgroundDrawable(null); //设置视图,actionBar即手机顶部的常驻空间,供页面的切换或标识 Trace.beginSection(TAG + " setup Views"); final ActionBar actionBar = getActionBar(); actionBar.setCustomView(R.layout.search_edittext);//放入“搜索编辑框” actionBar.setDisplayShowCustomEnabled(true); actionBar.setBackgroundDrawable(null); //搜索编辑框设计,首先同构ViewID找到控件 SearchEditTextLayout searchEditTextLayout = (SearchEditTextLayout) actionBar.getCustomView().findViewById(R.id.search_view_container); //猜测为输入时的智能提示 searchEditTextLayout.setPreImeKeyListener(mSearchEditTextLayoutListener); //为这个搜索编辑框绑定控制器 mActionBarController = new ActionBarController(this, searchEditTextLayout); //找到编辑控件 mSearchView = (EditText) searchEditTextLayout.findViewById(R.id.search_view); //监听编辑框文字输入 mSearchView.addTextChangedListener(mPhoneSearchQueryTextListener); //声控输入按钮 mVoiceSearchButton = searchEditTextLayout.findViewById(R.id.voice_search_button); //放大镜,位于文本编辑控件的左侧,并绑定Listener searchEditTextLayout.findViewById(R.id.search_magnifying_glass) .setOnClickListener(mSearchViewOnClickListener); //绑定开始查找按钮 searchEditTextLayout.findViewById(R.id.search_box_start_search) .setOnClickListener(mSearchViewOnClickListener); searchEditTextLayout.setOnClickListener(mSearchViewOnClickListener); //为searchEditTextLayout绑定callBack searchEditTextLayout.setCallback(new SearchEditTextLayout.Callback() { //返回上一次搜索 @Override public void onBackButtonClicked() { onBackPressed(); } @Override public void onSearchViewClicked() { //Floating action button (FAB)是一个带有环状阴影的圆形按键,位于 UI之上,用//于显示常用的操作,比如添加新条目、编写邮件等。 // 当键盘显示时隐藏FAB mFloatingActionButtonController.scaleOut(); } }); mIsLandscape = getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; //获取floatingActionButton的容器 final View floatingActionButtonContainer = findViewById( R.id.floating_action_button_container); //获取floatingActionButton ImageButton floatingActionButton = (ImageButton) findViewById(R.id.floating_action_button); //监听floatingActionButton floatingActionButton.setOnClickListener(this); //floatingActionButton控制,由于FAB是浮动的因此需要限定范围,并加以控制 mFloatingActionButtonController = new FloatingActionButtonController(this, floatingActionButtonContainer, floatingActionButton); //通过监听者都是this,猜测应该就是floatingActionButton ImageButton optionsMenuButton = (ImageButton) searchEditTextLayout.findViewById(R.id.dialtacts_options_menu_button); optionsMenuButton.setOnClickListener(this); //为搜索添加设置菜单 mOverflowMenu = buildOptionsMenu(searchEditTextLayout); //绑定监听者 optionsMenuButton.setOnTouchListener(mOverflowMenu.getDragToOpenListener()); //此处猜测为常用联系人 // Add the favorites fragment but only if savedInstanceState is null. Otherwise the // fragment manager is responsible for recreating it. if (savedInstanceState == null) { getFragmentManager().beginTransaction() .add(R.id.dialtacts_frame, new ListsFragment(), TAG_FAVORITES_FRAGMENT) .commit(); } else { mSearchQuery = savedInstanceState.getString(KEY_SEARCH_QUERY); mInRegularSearch = savedInstanceState.getBoolean(KEY_IN_REGULAR_SEARCH_UI); mInDialpadSearch = savedInstanceState.getBoolean(KEY_IN_DIALPAD_SEARCH_UI); mFirstLaunch = savedInstanceState.getBoolean(KEY_FIRST_LAUNCH); mShowDialpadOnResume = savedInstanceState.getBoolean(KEY_IS_DIALPAD_SHOWN); mActionBarController.restoreInstanceState(savedInstanceState); } final boolean isLayoutRtl = DialerUtils.isRtl(); //处理划屏动画加载,界面切换 if (mIsLandscape) {//左右滑屏为切换 mSlideIn = AnimationUtils.loadAnimation(this, isLayoutRtl ? R.anim.dialpad_slide_in_left : R.anim.dialpad_slide_in_right); mSlideOut = AnimationUtils.loadAnimation(this, isLayoutRtl ? R.anim.dialpad_slide_out_left : R.anim.dialpad_slide_out_right); } else {//上下滑屏为常驻返回等菜单显示与隐藏 mSlideIn = AnimationUtils.loadAnimation(this, R.anim.dialpad_slide_in_bottom); mSlideOut = AnimationUtils.loadAnimation(this, R.anim.dialpad_slide_out_bottom); } mSlideIn.setInterpolator(AnimUtils.EASE_IN); mSlideOut.setInterpolator(AnimUtils.EASE_OUT); //绑定滑屏监听者,这样才能实现功能 mSlideIn.setAnimationListener(mSlideInListener); mSlideOut.setAnimationListener(mSlideOutListener); //拖拽处理 mParentLayout = (FrameLayout) findViewById(R.id.dialtacts_mainlayout); mParentLayout.setOnDragListener(new LayoutOnDragListener()); floatingActionButtonContainer.getViewTreeObserver().addOnGlobalLayoutListener( new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { final ViewTreeObserver observer = floatingActionButtonContainer.getViewTreeObserver(); if (!observer.isAlive()) { return; } observer.removeOnGlobalLayoutListener(this); int screenWidth = mParentLayout.getWidth(); mFloatingActionButtonController.setScreenWidth(screenWidth); mFloatingActionButtonController.align( getFabAlignment(), false /* animate */); } }); Trace.endSection(); Trace.beginSection(TAG + " initialize smart dialing"); mDialerDatabaseHelper = DatabaseHelperManager.getDatabaseHelper(this); SmartDialPrefix.initializeNanpSettings(this); Trace.endSection(); Trace.endSection(); } |
以下为其布局XML
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/dialtacts_mainlayout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:focusable="true" android:focusableInTouchMode="true" android:clipChildren="false" android:background="@color/background_dialer_light"> <FrameLayout android:id="@+id/dialtacts_container" android:layout_width="match_parent" android:layout_height="match_parent" android:clipChildren="false"> <!-- The main contacts grid --> <FrameLayout android:layout_height="match_parent" android:layout_width="match_parent" android:id="@+id/dialtacts_frame" android:clipChildren="false" /> </FrameLayout> <FrameLayout android:id="@+id/floating_action_button_container" android:background="@drawable/fab_blue" android:layout_width="@dimen/floating_action_button_width" android:layout_height="@dimen/floating_action_button_height" android:layout_marginBottom="@dimen/floating_action_button_margin_bottom" android:layout_gravity="center_horizontal|bottom"> <ImageButton android:id="@+id/floating_action_button" android:background="@drawable/floating_action_button" android:layout_width="match_parent" android:layout_height="match_parent" android:contentDescription="@string/action_menu_dialpad_button" android:src="@drawable/fab_ic_dial"/> </FrameLayout> <!-- Host container for the contact tile drag shadow --> <FrameLayout android:id="@+id/activity_overlay" android:layout_height="match_parent" android:layout_width="match_parent"> <ImageView android:id="@+id/contact_tile_drag_shadow_overlay" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="gone" android:importantForAccessibility="no" /> </FrameLayout> </FrameLayout> |
1.3 拨号视图
拨号视图加载DialpadFragment .onCreateView():
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) { Trace.beginSection(TAG + " onCreateView"); Trace.beginSection(TAG + " inflate view"); //来自百度:在实际开发中LayoutInflater这个类还是非常有用的,它的作用类似于//findViewById()。不同点是LayoutInflater是用来找res/layout/下的xml布局文件,//并且实例化;而findViewById()是找xml布局文件下的具体widget控件(如Button、//TextView等)。具体作用: 1、对于一个没有被载入或者想要动态载入的界面,都需要使用//LayoutInflater.inflate()来载入; final View fragmentView = inflater.inflate(R.layout.dialpad_fragment, container, false); Trace.endSection(); Trace.beginSection(TAG + " buildLayer"); fragmentView.buildLayer(); Trace.endSection(); Trace.beginSection(TAG + " setup views"); mDialpadView = (DialpadView) fragmentView.findViewById(R.id.dialpad_view); mDialpadView.setCanDigitsBeEdited(true); mDigits = mDialpadView.getDigits(); mDigits.setKeyListener(UnicodeDialerKeyListener.INSTANCE); mDigits.setOnClickListener(this);//将自己设置为拨号按钮的监听者 mDigits.setOnKeyListener(this);//设置按键事件监听者 mDigits.setOnLongClickListener(this); mDigits.addTextChangedListener(this); mDigits.setElegantTextHeight(false); PhoneNumberFormatter.setPhoneNumberFormattingTextWatcher(getActivity(), mDigits); // 检查键盘的存在 View oneButton = fragmentView.findViewById(R.id.one); if (oneButton != null) {//如果存在设定监听者 configureKeypadListeners(fragmentView); } //del键设置 mDelete = mDialpadView.getDeleteButton(); if (mDelete != null) { mDelete.setOnClickListener(this); mDelete.setOnLongClickListener(this); } //空格键设置 mSpacer = fragmentView.findViewById(R.id.spacer); mSpacer.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (isDigitsEmpty()) { if (getActivity() != null) { return ((HostInterface) getActivity()).onDialpadSpacerTouchWithEmptyQuery(); } return true; } return false; } }); mDigits.setCursorVisible(false); // Set up the "dialpad chooser" UI; see showDialpadChooser(). mDialpadChooser = (ListView) fragmentView.findViewById(R.id.dialpadChooser); mDialpadChooser.setOnItemClickListener(this); //FAB设计 final View floatingActionButtonContainer = fragmentView.findViewById(R.id.dialpad_floating_action_button_container); final ImageButton floatingActionButton = (ImageButton) fragmentView.findViewById(R.id.dialpad_floating_action_button); floatingActionButton.setOnClickListener(this); mFloatingActionButtonController = new FloatingActionButtonController(getActivity(), floatingActionButtonContainer, floatingActionButton); Trace.endSection(); Trace.endSection(); return fragmentView; } |
Android6.0的phone应用源码分析(3)——phone 拨号UI分析相关推荐
- [导入]SunriseUpload.0.9.1的源码分析(七)
接着分析了几个小时的SunriseUpload.0.9.1的源码. 终于明白了作者的整体思路.在此就做一个总结. 首先,要想能上传很大的文件,我们就必须编写一个HttpModule来自己处理用户上传的 ...
- 分析开源项目源码,我们该如何入手分析?(授人以渔)
点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:牛人 20000 字的 Spring Cloud 总结,太硬核了~ 1 前言 本文接上篇文章跟大家聊聊我们为什么 ...
- Anaconda Python3.6 OpenCV4.1.0 Ubuntu 16.04源码编译
Anaconda Python3.6 OpenCV4.1.0 Ubuntu 16.04源码编译 转载于:https://blog.csdn.net/phdsky/article/details/782 ...
- android 5.0播放swf flash源码Demo
android 5.0播放swf flash源码Demo 安卓5.0flash播放源码 android flash 播放器 swf 由于之前webview方法播放flash在新的系统中不可用.所以so ...
- 点云配准2:icp算法在PCL1.10.0上的实现+源码解析
目录 本文最后实现的配准实例 点云配准系列 准备 程序结构 主程序 1.为什么要降采样 2.体素降采样原理 3.点云更新 icp 配准前的参数设置 icp配准算法内部 对应点对确定(determine ...
- 2022全新Ripro日主题V9.0升级修正版源码+美化包和插件
正文: 2022全新Ripro日主题V9.0升级修正版源码+美化包和插件,我现在分享的是RiPro9.0的二开版本,这个模板是本人花了Q找人弄到的,我给各位弄了2个美化包和全屏水印以及防复制插件. 模 ...
- (已更新)最新版本梦想贩卖机2.0.4小程序源码
环境要求 PHP+MYSQL+微擎+小程序 修复 小程序卡密资源库存为0时继续任务获取的bug 新增 后台资源列表页一键置顶.一键取消置顶功能 优化 后台资源列表页置顶排序优先 优化 去除小程序 ...
- 洗衣店v2.5.0微信小程序源码下载
新增功能 1.订单状态 通知 2.管理员手机端增加会员充值功能 3.优化下单页面功能 4.增加管理员端 跑腿人员结账功能 5.增加管理员收银功能 6.增加套餐卡(月/季/年卡)包月功能 7.增加会员功 ...
- 云开发喝酒神器2.0微信小程序源码 附搭建教程【源码好优多】
简介 云开发喝酒神器2.0微信小程序源码 附搭建教程 微信小程序云开发喝酒神器2.0微信小程序源码(带流量主),云开发小程序无法服务器即可搭建,配置有安装文档教程. 下方资源地址 云开发喝酒神器2.0 ...
最新文章
- 《深入理解Java虚拟机》读书笔记五
- boost::serial_executor相关的测试程序
- angular 动画_如何在Angular 6中使用动画
- 负数比较大小_人教版六下【第一单元】负数比较负数的大小
- 织梦cms第四版仿七猫技术导航源码 附安装教程
- 【AI视野·今日Robot 机器人论文速览 第二十期】Thu, 8 Jul 2021
- TreeView的基本使用 1205
- Ubuntu安装过程中的问题
- python 点击按钮 click_用selenium和Python单击“onclick”按钮
- python 速成学堂_Python 与数据科学入门
- LINUX SHELL中while循环和遍历参数
- HTML资源嗅探,scrapy-2 嗅探网站,解析HTML
- PMP考试扫盲:超详细的PMP考试小白攻略,必看篇
- 【批处理】快速批量修改特定文件夹的文件名
- mysql sniffer 安装_ubunt 安装mysql-sniffer
- 三星为Ativ S发布WP8更新
- 打印自身源代码的程序
- 机器学习老中医:利用学习曲线诊断模型的偏差和方差
- 纸箱制作机器人邮箱_纸箱机器人衣服制作方法
- 苹果x计算机怎么恢复,苹果手机怎样找回备忘录,电脑小白数据恢复全攻略
热门文章
- WebService:全网最全WebService技术简介
- WM SCM630 笔记 Unit 4 Putaway Control (1)
- linux:关于服务器终端自动掉线的问题总结
- 推荐美国简单的选项卡功能实现
- vim 从嫌弃到依赖(0)——概述
- java 导出txt,java生成txt,并写入内容,java读取txt文本内容
- MCS51霓虹灯_Proteus仿真
- [附源码]计算机毕业设计大学生心理测评系统Springboot程序
- dw php 网站上传,Dreamweaver怎么上传站点到服务器
- NodeJS 响应式故宫文化宣传网站计算机毕设源码61557