本文首发于我的Hexo博客:https://likianta.coding.me/2017/PassportPandoraPrj/1229172454/

先来看最终的效果图:

本章内容是根据上章制定好的规范进行的重新设计,其中主界面的两个分页布局变化幅度很大。

本章重点讲解右分页布局的重制,左分页布局会在下章讲解分组设计前补充。

一、重新制作右分页布局

在正式开始制作之前,我们需要预先下载两个软件:

  1. Axure PR 8:用于原型设计,然后根据此设计来实现工程布局
  2. X-Mind 8 Pro:用于制作思维导图,然后根据思维导图来实现工程代码的逻辑结构

虽然我们不是专业的设计师或产品经理,但是这两个软件的基本功能其实还是很容易上手的,下面就是简单的应用过程:

1. 使用Axure软件进行原型设计

下载好Axure PR 8后,打开软件界面如下所示:

第一步 开启网格辅助线

点击 菜单栏 - 布局 - 栅格和辅助线 - 勾选显示网格&进入网格设置:

在网格设置中的“网格”标签下勾选“显示网格”和“对齐网格”,设置Spacing = 40px,样式为线:

这样我们就成功地开启了网格辅助线。网格线有助于我们对组件规范、整齐地摆放,对于有整理癖的人来说非常好。

第二步 拖入一倍切图

在《关于Android开发中如何使用dp表示长宽 | Likianta Blog》一文中介绍了我们如何在布局中使用合适的切图作为参考,简单来说有以下几点:

  • 使用一倍切图(360px*640px)作为原型设计稿
  • 在Android开发中,使用Pixel作为默认的模拟器设备,则我们的xml文件中用360dp可以表示屏幕的总宽度,640dp代表屏幕的总高度,数值跟一倍切图稿是1:1的转换关系

另外值得一提的是Android的状态栏的高度是24dp,虚拟按键的高度是48dp,也就是说我们的一倍设计稿中有24+48px要从总高度中抛去,所以我们实际可设计的空间范围是:360px*568px。

下面在Axure中的标注和讲解我都会用“px”作为单位,然后到了制作Android xml布局文件的时候改用“dp”,由于数值之间是1:1的转换关系,所以大家不用太纠结 :)

第三步 制作右分页母版

本章我们的目的是重新制作右分页布局,所以把右分页中的固定元素做成母版(也就是模板),这样方便我们经常复用。

首先从左侧的组件库拖一个矩形2到中间的工作区,在属性面板中设置它的宽度为360px,高度为640px,位置的话就放在(40,80)吧:

(注:Axure中的位置都是从控件的左上角作为起始点计算的。)

依次拖入下面组件:

这样我们的右分页母版就完成了。

以后在每次复用时,只需将左下方的母版拖到中间的工作区,并右键“脱离母版”即可自由使用了。

第四步 制作布局里的元素(重点)

为了让设计显得简洁,这里将之前加入的很多元素都去除掉了,只保留了最核心的部分:

  • 头像及头像背景
  • 帐号栏
  • 密码栏
  • 备注栏
  • 扩展信息按钮
  • 保存按钮

另外根据预想的设计规范,按钮应该有丰富的响应动画。最典型的就是按下编辑框后应该有聚焦动画。为此我们给每个编辑框设置了三种常用状态和五种特定状态:


(不过在实际开发中发现这些设计所考虑到的东西是远远不够的。后面我们会一个问题一个问题地解决它们。)

第五步 添加说明注释和跳转链接

这项工作主要是在控件旁边写一些颜色、相对位置、注意事项这三类说明。主要用到的工具有:

顺便附上下载链接:该设计图原始文件(2017年12月30日)

如果你想要尽可能快地上手Axure这个软件,可以看一看我写的Axure从零快速上手 第一期 :)


二、在Android Studio中实现布局

有了原型设计图,你会发现制作xml布局比以前轻松了很多。

不过实际制作过程中会遇到一些比较严重的问题,比如下面提到的:

Q1:如何将Axure中的不透明度百分数转化为Android Studio中的两位十六进制数?

根据下面的透明度参照表:

透明度 不透明度 转换成十六进制数 备注
00% 100% FF 完全显示
05% 95% F2
10% 90% E5
15% 85% D8
20% 80% CC
25% 75% BF
30% 70% B2
35% 65% A5
40% 60% 99
45% 55% 8C 往上越来越“深”
50% 50% 7F 50%半透明
55% 45% 72 往下越来越“浅”
60% 40% 66
65% 35% 59
70% 30% 4C
75% 25% 3F
80% 20% 33
85% 15% 21
90% 10% 19
95% 05% 0C
100% 00% 00 完全透明

PS:

  • Axure和Android Studio用的都是不透明度,所以只需看第2列和第3列的对应关系即可
  • 所以我们在Axure中设计时也尽量取整5整10的不透明度,这样方便照着表直接转换

Q2:设计图中的编辑框内右侧的小箭头图标(>)怎么制作?

在Android Studio Asset网站你可以找到这个图标(图标名称“chevron”)。生成图表注意事项:

终于,我们下面要开始制作右分页布局了:


三、制作右分页布局(xml布局代码)

先看一下最终的效果图:

1. 将布局中用到的文字全部写到strings.xml文件中

res/values/strings.xml:

<resources><string name="app_name">AnyKey</string><string name="title_activity_login">AnyKey</string><!-- Strings related to login --><string name="prompt_email">Email</string><string name="prompt_password">Password (optional)</string><string name="action_sign_in">Sign in or register</string><string name="action_sign_in_short">Sign in</string><string name="error_invalid_email">This email address is invalid</string><string name="error_invalid_password">This password is too short</string><string name="error_incorrect_password">This password is incorrect</string><string name="error_field_required">This field is required</string><string name="permission_rationale">"Contacts permissions are needed for providing email completions."</string><!-- Strings related to page2 --><string name="title_hint">Title</string><string name="title_popup">▲TITLE</string><string name="title_error">Please Input Title Strings</string><string name="account_hint">Account</string><string name="account_popup">▲ACCOUNT</string><string name="pwd_hint">Password</string><string name="pwd_popup">▲PASSWORD</string><string name="note_hint">Take your note here.</string><string name="note_popup">◆NOTE</string></resources>

2. 制作xml布局

res/layout/page2.xml(原page_card_list.xml改名了):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@color/blaWindowBackground"><!-- 最外层是一个RelativeLayout,背景色与左分页背景同色 --><ScrollView
        android:layout_width="match_parent"android:layout_height="wrap_content"><!-- 在滑动布局中建一个相对布局。编辑框等控件都在此布局里面 --><RelativeLayout
            android:layout_width="match_parent"android:layout_height="wrap_content"><!-- 头像的背景,根据头像主色调来生成(方法在函数中实现) --><ImageView
                android:id="@+id/user_avatar_bg"android:layout_width="match_parent"android:layout_height="120dp"android:background="@color/blaThemeColorWeak" /><!-- 使用开源控件CircleTextImageView制作圆形头像 --><com.thinkcool.circletextimageview.CircleTextImageView
                android:id="@+id/user_avatar"android:layout_width="80dp"android:layout_height="80dp"android:layout_centerHorizontal="true"android:layout_marginTop="80dp"android:src="@drawable/avatar_test"app:citv_border_color="@color/blaWindowBackground"app:citv_border_width="2dp" /><!-- 下面是4个EditText,分别是“标题栏”、“帐号栏”、“密码栏”、“备注栏” --><!-- 标题栏属性:宽240dp,高28dp,水平居中,与头像相距40dp,背景是一个圆角矩形背景(后面会贴代码),限制为单行输入,文字颜色和hint颜色均在colors.xml文件中定义好了,这里就引用过来。最后设置文字风格为等宽字体(monospace),文字大小14sp,字体默认加粗 --><EditText
                android:id="@+id/user_title"android:layout_width="240dp"android:layout_height="28dp"android:layout_below="@id/user_avatar"android:layout_centerHorizontal="true"android:layout_marginTop="40dp"android:background="@drawable/edt_bg_normal"android:gravity="center_vertical"android:hint="@string/title_hint"android:inputType="textCapCharacters"android:paddingEnd="12dp"android:paddingStart="12dp"android:singleLine="true"android:textColor="@color/blaTextColorStrong"android:textColorHint="@color/blaTextColorWeak"android:textSize="14sp"android:textStyle="bold"android:typeface="monospace" /><!-- 接下来的“帐号栏”和“密码栏”的属性与“标题栏”一样,只是修改为各自的id、hint字符串内容不同而已 --><!-- 帐号栏 --><EditText
                android:id="@+id/user_account"android:layout_width="240dp"android:layout_height="28dp"android:layout_alignTop="@id/user_title"android:layout_centerHorizontal="true"android:layout_marginTop="60dp"android:background="@drawable/edt_bg_normal"android:gravity="center_vertical"android:hint="@string/account_hint"android:paddingEnd="12dp"android:paddingStart="12dp"android:singleLine="true"android:textColor="@color/blaTextColorStrong"android:textColorHint="@color/blaTextColorWeak"android:textSize="14sp"android:textStyle="bold"android:typeface="monospace" /><!-- 密码栏 --><EditText
                android:id="@+id/user_pwd"android:layout_width="240dp"android:layout_height="28dp"android:layout_alignTop="@id/user_title"android:layout_centerHorizontal="true"android:layout_marginTop="120dp"android:background="@drawable/edt_bg_normal"android:gravity="center_vertical"android:hint="@string/pwd_hint"android:inputType="textVisiblePassword"android:paddingEnd="12dp"android:paddingStart="12dp"android:singleLine="true"android:textColor="@color/blaTextColorStrong"android:textColorHint="@color/blaTextColorWeak"android:textSize="14sp"android:textStyle="bold"android:typeface="monospace" /><!-- 备注栏的设置有些不一样,区别在于:宽度为300dp,高度为自适应,但是最低高度值是“7”行(minLines=7),其背景用的是和上面不一样的背景资源(后面也会贴上背景代码),inputType类型是“textMultiLine” --><EditText
                android:id="@+id/user_note"android:layout_width="300dp"android:layout_height="wrap_content"android:layout_alignTop="@id/user_title"android:layout_centerHorizontal="true"android:layout_marginTop="180dp"android:background="@drawable/edt_bg_normal_note"android:gravity="start|top"android:hint="@string/note_hint"android:inputType="textMultiLine"android:minLines="7"android:padding="12dp"android:textColor="@color/blaTextColorStrong"android:textColorHint="@color/blaTextColorWeak"android:textSize="14sp"android:textStyle="bold"android:typeface="monospace" /><!-- 下面是编辑框上的提示文字,也就是这个部分:http://ozurciydg.bkt.clouddn.com/17-12-31/73887956.jpg --><!-- 标题栏提示文字。提示文字仅在框内有输入文字时出现,默认状态下是隐藏的 --><TextView
                android:id="@+id/user_title_txt"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignStart="@id/user_title"android:layout_alignTop="@id/user_title"android:layout_marginStart="-10dp"android:layout_marginTop="-18dp"android:text="@string/title_popup"android:textColor="@color/blaTextColorStrong"android:textSize="12sp"android:textStyle="bold"android:visibility="invisible" /><!-- 帐号栏提示文字 --><TextView
                android:id="@+id/user_account_txt"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignStart="@id/user_account"android:layout_alignTop="@id/user_account"android:layout_marginStart="-10dp"android:layout_marginTop="-18dp"android:text="@string/account_popup"android:textColor="@color/blaTextColorStrong"android:textSize="12sp"android:textStyle="bold"android:visibility="invisible" /><!-- 密码栏提示文字 --><TextView
                android:id="@+id/user_pwd_txt"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignStart="@id/user_pwd"android:layout_alignTop="@id/user_pwd"android:layout_marginStart="-10dp"android:layout_marginTop="-18dp"android:text="@string/pwd_popup"android:textColor="@color/blaTextColorStrong"android:textSize="12sp"android:textStyle="bold"android:visibility="invisible" /><!-- 备注栏提示文字 --><TextView
                android:id="@+id/user_note_txt"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignStart="@id/user_note"android:layout_alignTop="@id/user_note"android:layout_marginStart="-8dp"android:layout_marginTop="-18dp"android:text="@string/note_popup"android:textColor="@color/blaTextColorStrong"android:textSize="12sp"android:textStyle="bold"android:visibility="invisible" /><!-- 大家应该注意到上面的编辑框还没有写框内右侧的小按钮,下面用ImageView分别加上 --><!-- Icon Chevron related to EditTexts --><!-- 标题栏按钮。图标是从Android Studio Assets网站下载的 --><ImageView
                android:id="@+id/user_title_chevron"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignEnd="@id/user_title"android:layout_alignTop="@id/user_title"android:layout_marginEnd="6dp"android:layout_marginTop="9dp"android:src="@drawable/icon_chevron_right" /><!-- 帐号栏按钮 --><ImageView
                android:id="@+id/user_account_chevron"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignEnd="@id/user_account"android:layout_alignTop="@id/user_account"android:layout_marginEnd="6dp"android:layout_marginTop="9dp"android:src="@drawable/icon_chevron_right" /><!-- 密码栏按钮 --><ImageView
                android:id="@+id/user_pwd_chevron"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignEnd="@id/user_pwd"android:layout_alignTop="@id/user_pwd"android:layout_marginEnd="6dp"android:layout_marginTop="9dp"android:src="@drawable/icon_chevron_right" /><!-- 备注栏没有chevron按钮 --></RelativeLayout></ScrollView></RelativeLayout>

其中需要用到的背景布局:

1. 标题栏、帐号栏、密码栏背景布局文件:res/drawable/edt_bg_normal.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"><!-- 被按下时的状态(正在按。这个状态很短暂) --><!-- 此时圆角矩形的边框颜色与框内填充颜色融为一体,为纯白色 --><item android:state_pressed="true"><shape android:shape="rectangle"><solid android:color="@color/blaEdtColorActivated" /><corners android:radius="6dp" /></shape></item><!-- 按下后的状态(聚焦状态) --><!-- 此时的状态和上一个一样。不过我们会在代码中给它附加上阴影效果 --><item android:state_focused="true"><shape android:shape="rectangle"><solid android:color="@color/blaEdtColorActivated" /><corners android:radius="6dp" /></shape></item><!-- 普通状态(未获得焦点时的状态) --><!-- 边框颜色为浅灰色(与hint文字颜色一致),框内填充色为纯白色 --><item android:state_window_focused="false"><shape android:shape="rectangle"><solid android:color="@color/blaEdtColorNormal" /><stroke android:width="1dp" android:color="@color/blaTextColorWeak" /><corners android:radius="6dp" /></shape></item></selector>

2. 备注栏的背景布局文件:res/drawable/edt_bg_normal_note.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"><!-- 被按下时的状态(正在按。这个状态很短暂) --><!-- 省略不写 --><!-- 按下后的状态(聚焦状态) --><!-- 这里引用了一个图片资源。在下一小节会对其讲解 --><item android:drawable="@drawable/edt_bg_shadow" android:state_focused="true" /><!-- 普通状态(未获得焦点时的初始状态。和上一个背景的初始状态一样) --><item android:state_window_focused="false"><shape android:shape="rectangle"><solid android:color="@color/blaEdtColorNormal" /><stroke android:width="1dp" android:color="@color/blaTextColorWeak" /><corners android:radius="6dp" /></shape></item></selector>

3. 阴影该怎么制作?

Android 5.0加入了高度(elevation)属性,只需要在EditText中设置elevation="6"即可生成高度为6dp(z=6)的阴影。

但是用这个方法做出来的阴影效果并不好看:

并且elevation属性也不支持调节阴影方向、blur值以及阴影颜色。为了实现和Axure软件同样的效果,我们要考虑采用哪种阴影方案:

方案 说明 缺点
1 增加elevation高度 效果不好,是向四周扩散的
2 看看有没更改阴影颜色的代码 默认不支持,自定义太麻烦
3 使用嵌套结构layer-list 阴影效果不好,没办法做出来设计图中的效果
4 使用translation x & y 会造成点击错位(不过影响不大),实际测试还是觉得阴影的效果不好
5 使用开源组件——shadow layout的功能特性非常符合需求 shadow-layout需要给每个view套一个外壳,且自带4dp内间距,导致提示文字和按钮的相对位置一直调不准
6 使用CardView CardView缺点见这里:Home · dmytrodanylyk/shadow-layout Wiki
7 使用点九图制作 ok

最终我们选择了点九图制作,这里推荐使用Android Shadow Generator在线网站来生成点九图。你可以自定义边角弧度、阴影偏离方向、blur值以及阴影颜色,理论上可以完美实现和Axure设计图一致的阴影效果:

注意:点九图参数设置:

不同的分辨率对应的参数值是不一样的。总的来说我们需要制作以下三种点九图:

切图 Radius(边框圆角半径)/px x偏移/px y偏移/px blur 备注
一倍切图(360px*640px) 6 5 5 8 一倍切图就是我们在设计稿中的分辨率
二倍切图(720px*1280px) 12 10 10 16 二倍切图就是xhdpi等级
三倍切图(1080px*1920px) 18 15 15 24 三倍切图就是xxhdpi等级。
我们使用的Pixel模拟器就是这个等级,其dp-px换算关系为1dp=3px

因此我们最好做三种贴图并放到对应的分辨率目录(不过为了测试方便,这里我只做了三倍切图的阴影)。

属性如下:

Basic Fill & Outline Advanced Preview 备注
Round = 18 Unenabled Box Size width = 144 / /
Shadow blur = 24 / Box Size height = 144 / /
Shadow color: rgba(0,0,0,0.35) / / / /
Shadow offset X = 15 / / / /
Shadow offset y = 15 / / / 文件下载:edt_bg_shadow.9.png

把下载下来的点九图阴影复制到drawable目录下,接着我们给右分页布局中的EditText控件添加阴影:

res/layout/page2.xml

<RelativeLayout><ScrollView><RelativeLayout><!-- 头像的背景,根据头像主色调来生成(方法在函数中实现) --><ImageView ... /><!-- 使用开源控件CircleTextImageView制作圆形头像 --><com.thinkcool.circletextimageview.CircleTextImageView ... /><!-- EditText shadow on the behind --><!-- 1. 阴影放在EditText之前写,这样可以让后写的控件压到先写的阴影之上 --><!-- 2. 阴影的长宽比EditText各多出10dp,这个是目测出来的结果([WHY?](http://ozurciydg.bkt.clouddn.com/17-12-31/86825566.jpg)) --><!-- 3. 阴影默认状态是隐藏的,只有在EditText被点击时才会被触发 --><!-- 标题栏的阴影 --><ImageView
            android:id="@+id/user_title_shadow"android:layout_width="250dp"android:layout_height="38dp"android:layout_alignStart="@id/user_title"android:layout_alignTop="@id/user_title"android:background="@drawable/edt_bg_shadow"android:visibility="invisible" /><!-- 帐号栏的阴影 --><ImageView
            android:id="@+id/user_account_shadow"android:layout_width="250dp"android:layout_height="38dp"android:layout_alignStart="@id/user_account"android:layout_alignTop="@id/user_account"android:background="@drawable/edt_bg_shadow"android:visibility="invisible" /><!-- 密码栏的阴影 --><ImageView
            android:id="@+id/user_pwd_shadow"android:layout_width="250dp"android:layout_height="38dp"android:layout_alignStart="@id/user_pwd"android:layout_alignTop="@id/user_pwd"android:background="@drawable/edt_bg_shadow"android:visibility="invisible" /><!-- 由于备注栏的高度是随文本多少而动态变化的,使用阴影的话需要在代码中动态匹配,一方面逻辑比较复杂,另一方面实测发现设定了“inputType="textMultiLines"”属性的EditText无法监听按键事件,给我们的匹配方法造成了致命的阻碍。因此我们不制作备注栏阴影,改用了另一种更省事的方法(下面会说) --><!-- EditText --><EditText android:id="@+id/user_title" ... /><EditText android:id="@+id/user_account" ... /><EditText android:id="@+id/user_pwd" ... /><EditText android:id="@+id/user_note" ... />...</RelativeLayout></ScrollView>
</RelativeLayout>

由于备注栏的高度是随文本多少而动态变化的,使用阴影的话需要在代码中动态匹配,一方面逻辑比较复杂,另一方面实测发现设定了“inputType=”textMultiLines””属性的EditText无法监听按键事件,给我们的匹配方法造成了致命的阻碍。因此我们不得不手动将点九图阴影直接写入到备注栏的背景中去:

res/drawable/edt_bg_normal_note.xml

<selector xmlns:android="http://schemas.android.com/apk/res/android"><!-- 按下后的状态(聚焦状态) --><!-- 这里引用了一个图片资源 --><item android:drawable="@drawable/edt_bg_shadow" android:state_focused="true" /><!-- 普通状态 --><item ... /></selector>

四、启动测试

由于我们对右分页布局进行了大换血,原MainActivity中的很多代码可能不能再使用了,为了保证本次测试成功,我们需要适当地对MainActivity进行一番改动(主要就是把以前的关联代码注释掉或删除掉):

MainActivity.java

package com.likianta.anykey;import android.content.Context;
import android.content.Intent;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;import com.thinkcool.circletextimageview.CircleTextImageView;import java.util.ArrayList;
import java.util.List;public class MainActivity extends AppCompatActivity implements View.OnClickListener {List<CardData> cardDataList = new ArrayList<>();// 以下变量是与分页相关的变量private View page1; // 左分页private View page2; // 右分页private ViewPager viewPager; // 控制分页逻辑的容器private ArrayList<View> pageList; // 装载分页元素的容器// 以下变量是与左分页相关的控件private RecyclerView recyclerView; // 卡片列表private CardAdapter cardAdapter;private DataAdapter dataAdapter;private List<Card> cardList = new ArrayList<>(); // 卡片数据// 以下变量是与右分页相关的控件private CircleTextImageView userAvatar;private EditText userTitle;private EditText userAccount;private EditText userPassword;private EditText userNote;private ImageView userTitleShadow;private ImageView userAccountShadow;private ImageView userPasswordShadow;private ImageView userTitleChevron;private ImageView userAccountChevron;private ImageView userPasswordChevron;private TextView userTitleText;private TextView userAccountText;private TextView userPasswordText;private TextView userNoteText;private Button userSaveButton;private String groupName = "未分类"; // temple conversion string@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 开始绑定按钮initBinding();// 初始化左分页initPager1();// 初始化右分页(在onCreate方法中没必要做。在点击保存按钮后使用该方法来清空右分页的表单编辑框)// initPager2();// 监听按钮点击// testButton button = (Button) findViewById(R.id.btn_test);button.setOnClickListener(this);}public void initBinding() {viewPager = (ViewPager) findViewById(R.id.view_pager);// 用LayoutInflater来绑定布局LayoutInflater inflater = getLayoutInflater();page1 = inflater.inflate(R.layout.page1, null); // 预加载左分页page2 = inflater.inflate(R.layout.page2, null); // 预加载右分页pageList = new ArrayList<>(); // pageList被实例化为装载View元素的数组pageList.add(page1);pageList.add(page2);// add的先后顺序不要搞错,先add的就是array[0]位置的元素了// 绑定分页的按钮recyclerView = (RecyclerView) page1.findViewById(R.id.page1_recycler);// bind page2 viewsuserAvatar = (CircleTextImageView) page2.findViewById(R.id.user_avatar);userTitle = (EditText) page2.findViewById(R.id.user_title);userTitleShadow = (ImageView) page2.findViewById(R.id.user_title_shadow);userTitleText = (TextView) page2.findViewById(R.id.user_title_txt);userTitleChevron = (ImageView) page2.findViewById(R.id.user_title_chevron);userAccount = (EditText) page2.findViewById(R.id.user_account);userAccountShadow = (ImageView) page2.findViewById(R.id.user_account_shadow);userAccountText = (TextView) page2.findViewById(R.id.user_account_txt);userAccountChevron = (ImageView) page2.findViewById(R.id.user_account_chevron);userPassword = (EditText) page2.findViewById(R.id.user_pwd);userPasswordShadow = (ImageView) page2.findViewById(R.id.user_pwd_shadow);userPasswordText = (TextView) page2.findViewById(R.id.user_pwd_txt);userPasswordChevron = (ImageView) page2.findViewById(R.id.user_pwd_chevron);userNote = (EditText) page2.findViewById(R.id.user_note);userNoteText = (TextView) page2.findViewById(R.id.user_note_txt);}public void initPager1() {PagerAdapter pagerAdapter = new PagerAdapter() {// https://www.cnblogs.com/weixing/archive/2013/10/11/3363951.html// 获取页卡总数量@Overridepublic int getCount() {return pageList.size();}// 判断是否由对象生成界面,这个很重要,是用来把pageView数组中的page1和page2生成到当前布局中的方法@Overridepublic boolean isViewFromObject(View view, Object object) {return view == object;}// 使从ViewGroup中移出当前View@Overridepublic void destroyItem(ViewGroup arg0, int arg1, Object arg2) {((ViewPager) arg0).removeView(pageList.get(arg1));}// 返回一个对象,这个对象表明了PagerAdapter适配器选择哪个对象放在当前的ViewPager中@Overridepublic Object instantiateItem(ViewGroup arg0, int arg1) {//这个方法用来实例化页卡((ViewPager) arg0).addView(pageList.get(arg1));return pageList.get(arg1);}};viewPager.setAdapter(pagerAdapter); // 绑定适配器// 设置viewPager的初始界面为第一个界面viewPager.setCurrentItem(0); // 这里的0对应的是viewPager[0],也就是page1了// 添加切换界面的监听器viewPager.addOnPageChangeListener(new MyOnPageChangeListener());// 为左分页加载卡片列表//PageRender();}public void initPager2() {userTitle.setText("");userAccount.setText("");userPassword.setText("");userNote.setText("");// 不知道什么原因,如果在此处重置头像为默认,会发现卡片头像也会“突变”为默认。// 而把重置头像的业务放到页面监听里面就不会引起此bug,所以不得已把头像重置的代码放到MyOnPageChangeListener的case1里面了}// 渲染分页public void PageRender() {cardDataList = new SavedToMySharedPrefs(MainActivity.this, "card_data").getCardData();dataAdapter = new DataAdapter(cardDataList);recyclerView.setLayoutManager(new LinearLayoutManager(this));recyclerView.setAdapter(dataAdapter);}@Overridepublic void onClick(View view) {switch (view.getId()) {case R.id.btn_test:int w = userNote.getWidth();int h = userNote.getHeight();LogUtil.d("ma user title edit text width is: " + w);LogUtil.d("ma user title edit text height is: " + h);default:}}// 判断从GroupActivity来的返回值@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent intent) {switch (requestCode) {case 1:if (resultCode == RESULT_OK) {groupName = intent.getStringExtra("get groupName");LogUtil.d("ma you get the returned result (groupName): " + groupName);}break;default:}}@Overridepublic void onDestroy() {super.onDestroy();// Save all data.new SavedToMySharedPrefs(MainActivity.this, "card_data").setCardData(cardDataList);}// 页面滚动监听器功能,实现标签页左右滑动切换效果public class MyOnPageChangeListener implements ViewPager.OnPageChangeListener {@Overridepublic void onPageSelected(int index) {switch (index) {case 0:InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);inputMethodManager.hideSoftInputFromWindow(MainActivity.this.getCurrentFocus().getWindowToken(), 0); // 强制隐藏软键盘break;case 1:userAvatar.setText("");userAvatar.setImageResource(R.drawable.avatar_test);break;}}@Overridepublic void onPageScrolled(int arg0, float arg1, int arg2) {}@Overridepublic void onPageScrollStateChanged(int arg0) {}}}

另外对activity_main.xml也做了大幅度简化:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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="@color/colorWhite"tools:context="com.likianta.anykey.MainActivity"><!-- 分页容器 --><android.support.v4.view.ViewPager
        android:id="@+id/view_pager"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_alignParentTop="true"></android.support.v4.view.ViewPager><Button
        android:id="@+id/btn_test"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="test"/></RelativeLayout>

实际测试效果

(这里用的是下一章的图。里面增加了按钮动画和文本判断)

经过精心的制作后,我们本章的主要任务就完成了。

通过这次制作过程我们会发现,在设计时有很多细节都是考虑不到的,比如说EditText的inputType、颜色值的百分比转换、阴影的制作问题等。通过自己的设计和实现可以对产品的开发有更多认识。

下章将讲解如何制作按钮的点击动画,以及根据文本内容适用不同的背景资源。

下章链接:https://likianta.coding.me/2017/PassportPandoraPrj/1231204322/


五、扩展环节

1. 如何让EditText默认不获取焦点?

在第一次打开后滑动到右分页,会发现标题栏会自动获取到焦点。为了让它不默认获取焦点,我们需要让别的View率先抢占焦点(只需增加两行代码):

page2.xml

<RelativeLayout><ScrollView><RelativeLayout><!-- 头像的背景 --><ImageView ... /><!-- 圆形头像。让圆形头像抢占焦点 --><com.thinkcool.circletextimageview.CircleTextImageView
            ...android:focusable="true"android:focusableInTouchMode="true" /><!-- EditText shadow on the behind --><ImageView android:id="@+id/user_title_shadow" ... /><ImageView android:id="@+id/user_account_shadow" ... /><ImageView android:id="@+id/user_pwd_shadow" ... /><!-- EditText --><EditText android:id="@+id/user_title" ... /><EditText android:id="@+id/user_account" ... /><EditText android:id="@+id/user_pwd" ... /><EditText android:id="@+id/user_note" ... />...</RelativeLayout></ScrollView>
</RelativeLayout>

2. 自定义光标样式

Android默认的光标是粉红色的,我们可以修改为自定义的光标样式。

首先创建一个背景布局res/drawable/shape_cursor.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle"><size android:width="2dp" /><solid android:color="@color/colorBlack" />
</shape>

然后让右分页的编辑框的光标全部装载此样式:

page2.xml

<RelativeLayout><ScrollView><RelativeLayout>...<!-- EditText --><EditText
            android:id="@+id/user_title"...android:textCursorDrawable="@drawable/shape_cursor" /><EditText
            android:id="@+id/user_account"...android:textCursorDrawable="@drawable/shape_cursor" /><EditText
            android:id="@+id/user_pwd"...android:textCursorDrawable="@drawable/shape_cursor" /><EditText
            android:id="@+id/user_note"...android:textCursorDrawable="@drawable/shape_cursor" />...</RelativeLayout></ScrollView>
</RelativeLayout>

3. 为备注栏制作专用的阴影图

新的点九图更改了阴影的x偏移值,使备注栏的左侧不至于过白,和背景分不清楚。

文件下载:edt_bg_shadow_note.9.png

res/drawable/edt_bg_normal_note.xml中修改为:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"><item android:drawable="@drawable/edt_bg_shadow_note" android:state_focused="true" />...</selector>

参考

  1. 【新提醒】关于虚拟按键高度,懂得且感兴趣过来探讨一下 - LG G2 安卓论坛 机锋论坛 http://bbs.gfan.com/android-7971983-1-1.html
  2. Android 5.x新特性之elevation(阴影),tinting(着色)以及clipping(剪裁) - 笨笨丫头~双 - 博客园 https://www.cnblogs.com/ai394495243/p/5075758.html
  3. Android 动画 - TranslateAnimation位移动画 - CSDN博客 http://blog.csdn.net/shibin1990_/article/details/51602564
  4. 颜色相关
    1. ANDROID TEXTVIEW 设置字体颜色 - CSDN博客 http://blog.csdn.net/maigan323/article/details/7026218/
    2. 百分比换算十六进制透明度 - CSDN博客 http://blog.csdn.net/lyltiger/article/details/48292419
    3. android颜色渐变如何实现从四周往中心渐变 或者从中心往四周渐变 都行,不是 从左往右_百度知道 https://zhidao.baidu.com/question/329382365.html
    4. colorAccent,colorPrimary,colorPrimaryDark……来这里你就明白了 - Louie81的博客 - CSDN博客 http://blog.csdn.net/Louie81/article/details/78789285
  5. EditText相关
    1. Android:EditText 多行显示及所有属性 - CSDN博客 http://blog.csdn.net/qyf_5445/article/details/8651740
    2. Android 设置EditText光标Cursor颜色及粗细 - 享受技术带来的快乐 - CSDN博客 http://blog.csdn.net/jdsjlzx/article/details/45075865
    3. Android 如何让EditText不自动获取焦点 - java豆子 - 博客园 https://www.cnblogs.com/error404/archive/2012/12/28/2837294.html
    4. http://m.blog.csdn.net/hotlinhao/article/details/41821279
    5. Android中EditView TextView (padding失效)使用setBackgroundDrawable或setBackgroundResource则xml中设置的 Padding失效 - 风一样的男人 - CSDN博客 http://blog.csdn.net/a2241076850/article/details/73481378
    6. Android 对TextView添加删除线,下划线,加粗,斜体等效果 - CSDN博客 http://blog.csdn.net/lzyang187/article/details/50695563
    7. 真正解决TextView行间距、字间距的问题 - CSDN博客 http://blog.csdn.net/peter6359312/article/details/52370949

09 Anykey右分页重新设计相关推荐

  1. 04 Anykey右分页布局TableLayout

    1. 先看最终效果图 右分页布局中的控件比较多,难度也比之前的三章难很多. 这里主要分成三大块来考虑:头像布局.常规填表界面以及所有功能按钮(本章只是做出个外形,数据绑定逻辑会在下章再讲). 所以今天 ...

  2. JavaWeb.09.新闻之分页功能

    怎么实现分页功能? 目录: 关于分页? 实现数据分页? 分页优化: 模糊查询的优化: 数据库编写SQL语句?         具体代码展示? 关于分页: 在实现分页功能之前,咱们可以先将主页(inde ...

  3. ​经典算法09 堆排序

    ​经典算法09 堆排序 ​ 活动地址:CSDN21天学习挑战赛 *学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩:迟一天就多一天平庸的困扰. 简介 堆排序和简单选择排序一样属于选择排序 简单排序 ...

  4. Python爬虫小实践:爬取任意CSDN博客所有文章的文字内容(或可改写为保存其他的元素),间接增加博客访问量...

    Python并不是我的主业,当初学Python主要是为了学爬虫,以为自己觉得能够从网上爬东西是一件非常神奇又是一件非常有用的事情,因为我们可以获取一些方面的数据或者其他的东西,反正各有用处. 这两天闲 ...

  5. 简单NLP分析套路(1)----语料库积累之3种简单爬虫方式应对大部分网站

    目录 近期听课的思考 语料库的记录 3种爬虫 urllib.request + BeautifulSoup scrapy 与xpath 使用selenium 模拟浏览器行为 新的改变 相关链接 未完待 ...

  6. 中国天气网接口说明及城市编码全部 为天气开发做铺垫

    中国天气网接口及城市编码全部 为天气开发做铺垫 中国天气网接口: 6天预报:http://m.weather.com.cn/data/101010100.html 实时预报:http://www.we ...

  7. webmagic学习之路-2:采集安居客经纪人列表

    相比较 1 稍微成熟了一点,会用的东西多了. 正则用的不好,很多东西不会,大神轻喷! package com.action; import java.util.ArrayList; import ja ...

  8. SQL Server 2005 版本说明

    SQL Server 2005 功能比较 发布日期: 2005/09/14 Microsoft 已重新设计了 SQL Server 2005 产品系列,有 Express.Workgroup.Stan ...

  9. juery笔记常用代码

    //添加样式---本节点的兄弟节点 $(this).next(".bankverify").find(".verifyone").eq(0).addClass( ...

  10. uniapp中的view高度设置100%

    1.在APP.vue文件添加如下代码 <script>export default {data() {return {globalData: {},}},onLaunch: functio ...

最新文章

  1. 买台式电脑还是笔记本好?
  2. 设计桑基图_教你用pyecharts制作交互式桑基图,赶快学起来吧!
  3. 犀牛建模软件的英文语言包_使用tidytext和textmineR软件包在R中进行主题建模(
  4. json解析对象时指定解析_不解析,使用解析对象
  5. php 经典的算法,PHP各种经典算法
  6. java数据结构 -链表 -获取有效节点个数,单链表中倒数k个节点
  7. 为什么复制粘贴格式总是出错_想把图片转换成pdf格式怎么做?你找对方法了吗...
  8. mysql查询最接近的记录
  9. sdut3138: N!(计算n!中结尾零的个数)
  10. vc++/c++ 汉字取拼音首字母
  11. 新榜微信文章抓取客户端(APSpider)
  12. du和df命令的区别
  13. 将pdf文件转换成word,csv文件
  14. 怎样让健康码截图合并一张图片_健康码拼图
  15. 折腾词库,一个词库互转程序
  16. XMind 2021 Mac 去水印教程
  17. JUC-05-ForkJoin,Future(了解即可)
  18. RISC-V学习基础(五)
  19. word不能粘贴文字问题
  20. 学计算机核显足够了吗,独立显卡、核心显卡和集成显卡的区别

热门文章

  1. 斗兽棋在线游戏HTML5小游戏,js --斗兽棋游戏
  2. docker 入门优质文章
  3. nbiot电信平台android,nbiot之bc26 连接电信网联网平台
  4. java 读取word页码
  5. 升级macOS Catalina 后辅助功能空白无法添加的问题
  6. Java+SQLServer实现——网上图书馆借还管理系统
  7. 遥感方向SCI期刊整理
  8. 奈式准则和香农定理(附例题)
  9. SAS首席科学家:如何选择机器学习算法?
  10. 苹果手机科学计算机怎样调用,iOS上的表达式科学计算器Calculator i++使用说明