从概念设计到安卓实现, 第一部分(译)

从概念设计到安卓实现, 第一部分(译)

泡在网上的日子 / 文 发表于2017-03-17 17:27 第720次阅读 概念设计,DataBinding,ConstraintLayout
0

编辑推荐:稀土掘金,这是一个针对技术开发者的一个应用,你可以在掘金上获取最新最优质的技术干货,不仅仅是Android知识、前端、后端以至于产品和设计都有涉猎,想成为全栈工程师的朋友不要错过!

英文原文:From design to android, part 1 

多亏了 Dribbble 和 MaterialUp这样的设计平台,我们这些开发者才有机会接触到大量的概念设计资源。尽管如此,有时候有些细节几乎是不可能实现的,部分用户体验并没有被考虑。

鉴于此,我觉得建立一个这样的项目会比较有意思:选择一些Dribbble 或者 MaterialUp上的设计资源,在安卓上实现它们,然后撰写一些列的文章来讲解实现的细节以及我认为比较重要的安卓界面实现技巧。

概念设计

这是我为第一部分选择的概念设计,简单但是足以涵盖一些有趣的话题了,比如 ConstraintLayout & chainsDataBinding,UI层次结构性能的重要性以及scenes(场景)

concept.gif

让我们开始吧!

支持库中的Bottom sheets

在演示图中,bottom sheet被用来引导用户完成购买过程。在安卓中你可以找到几个第三方库来实现这种视图,比如Umano的 AndroidSlidingUpPanel library

其实最近 bottoms sheets被引入了 design support library,因此我决定在这里使用它,学习该如何使用。

bottom_sheets (1).gif

Bottom sheets有两种使用方式,一种是Bottom sheets作为main view 的一部分(在 CoordinatorLayout中的一个viewgroup上使用BottomSheetBehavior),另一种是模态对话框似的Bottom sheets,使用BottomSheetDialogFragment来实现。

对于我们的例子我选择BottomSheetDialogFragment ,因为这里的信息是以模态的形式显示的。这种Bottom sheets实现的代码和DialogFragment的用法类似。

HomeActivity.java

   
   
  1. OrderDialogFragment.newInstance(
  2.   fakeProducts.get(position))
  3.     .show(getSupportFragmentManager(),null);

OrderDialogFragment.java

   
   
  1.   @Override
  2. public View onCreateView(LayoutInflater inflater,
  3.     ViewGroup container,Bundle savedInstanceState) {
  4.  
  5.     super.onCreateView(inflater,
  6.         container, savedInstanceState);
  7.  
  8.     binding = FragmentOrderFormBinding.inflate(
  9.         inflater, container, false);
  10.  
  11.     return binding.getRoot();
  12. }

ConstraintLayout

Google I/O '16上发布的这个强大的布局控件最近迎来了它的稳定版本(1.0.2)。

这个控件的最大好处在于,它可以让你以最扁平的层次,构造复杂的,自适应的布局。

1489742767127696.png

通常建议安卓的布局中要避免使用层次很深的视图结构,因为这样会降低性能,而且会增加UI绘制到屏幕的时间。而如果使用ConstraintLayout,这样的要求自动就满足了。

constraint_hierarchy.png

基本地,ConstraintLayout的工作原理类似RelativeLayout,即定义视图与屏幕之间的关系。但是ConstraintLayout除了性能更好之外,在Android Studio的图形编辑器中的表现也真的很好。

除此之外还有更多有趣的机制比如view之间的chain(不同的view相互约束),或者guidelines。

chain的使用

假设我们有两个view,A和B,分别被约束在屏幕的右边沿和左边沿。如果A设定在B的左边,而B设定在A的右边,这样这组view就会被特殊处理,在约束布局中这样的情况被称之为chain。

chain1.png

使用Android Studio的布局编辑器的上下文菜单很容易就可以创建一个chain。默认创建的是spread chain,即视图均匀分布。

chain_creation (1).gif

Chain 类型


在这个例子中,我们只使用spread 和 packed chain,但是你可以根据自己的需要选择,最近谷歌对ConstraintLayout的文档增加了对chain的说明,没有理由不用。

被选中view的过渡动画

这看起来比较简单,每当用户点击一个产品参数的时候,被选择的view就过渡到左下角的标签旁边。

为此我们在被点击的的view的parent中添加一个新的view。

OrderDialogFragment.java

   
   
  1. private void transitionSelectedView(View v) {
  2.     final View selectionView = createSelectionView(v);
  3.  
  4.     binding.mainContainer.addView(selectionView);
  5.  
  6.     startCloneAnimation(selectionView, getTargetView(v));
  7. }

然后使用TransitionManagerbeginDelayedTransition来做过渡动画。这个方法将检测布局是否有变化,如果有,使用传入的transition来执行动画。

OrderDialogFragment.java

   
   
  1. private void startCloneAnimation(View clonedView, View targetView) {
  2.     clonedView.post(() -> {
  3.         TransitionManager.beginDelayedTransition(
  4.             (ViewGroup) binding.getRoot(), selectedViewTransition);
  5.  
  6.         // 触发transition
  7.         clonedView.setLayoutParams(SelectedParamsFactory
  8.             .endParams(clonedView, targetView));
  9.     });
  10. }

ViewSwitcher

ViewSwitcher,Android SDK一个并不十分流行的控件,它可以用进入和退出动画来切换两个view。这和我们购买过程中在代表两个步骤的布局之间切换是完全符合的。
fragment_order_form.xml

   
   
  1. <ViewSwitcher
  2.     android:id="@+id/switcher"
  3.     android:layout_width="match_parent"
  4.     android:layout_height="wrap_content"
  5.     android:inAnimation="@anim/slide_in_right"
  6.     android:outAnimation="@anim/slide_out_left"
  7.     >
  8.  
  9.     <include
  10.         android:id="@+id/layout_step1"
  11.         layout="@layout/layout_form_order_step1"
  12.         />
  13.  
  14.     <include
  15.         android:id="@+id/layout_step2"
  16.         layout="@layout/layout_form_order_step2"
  17.         />
  18. </ViewSwitcher>

switcher.gif

OrderDialogFragment.java

   
   
  1. private void showDeliveryForm() {
  2.     binding.switcher.setDisplayedChild(1);
  3.     initOrderStepTwoView(binding.layoutStep2);
  4. }

Databinding(数据绑定)

这个设计的实现我使用了Databinding,对我来说在一个对象中包含所有的布局结构是可以接受的,但是Databading还有其它一些机制值得一提。

节省click listener的书写次数

因为这些布局有大量的listener需要处理,我决定为用Databinding绑定一个listener对象来处理onClick。在xml中,为每个view的onClick属性设置方法名,然后事件就会定向到listener对象的相应方法中。

layout_form_order_step1.xml

   
   
  1. <data>
  2.     <variable
  3.         name="listener"
  4.         type="com.saulmm.cui.OrderDialogFragment.Step1Listener"
  5.         />
  6. </data>
  7.  
  8. <CircleImageView
  9.     android:id="@+id/img_color_blue"
  10.     style="@style/Widget.Color"
  11.     android:onClick="@{listener::onColorSelected}"
  12.     />
  13.  
  14. <CircleImageView
  15.     android:id="@+id/img_color_blue"
  16.     style="@style/Widget.Color"
  17.     android:onClick="@{listener::onColorSelected}"
  18.     />

OrderDialogFragment.java

   
   
  1. layoutStep1Binding.setListener(new Step1Listener() {
  2.     @Override
  3.     public void onSizeSelected(View v) {
  4.         // ...
  5.     }
  6.  
  7.     @Override
  8.     public void onColorSelected(View v) {
  9.         // ...
  10.     }
  11. })

使用Spannables + databinding + ConstraintLayout来减少view

让我们花点时间来思考如何实现下面这部分设计

1489937099138454.png

一种办法是每个item设置一个垂直的LinearLayout,然后3个item被包含在一个水平的LinearLayout中,然后再用一个LinearLayout包裹两个水平LinearLayout以及两个文本标签控件。

平时别这样做

bad_hierarchy.png

这样看起来并不好,对吧?前面我们谈到了扁平结构的重要性,所以正确的做法是使用ConstrainLayout作为容器。

每一个item都是LinearLayout的话开销很大的,其实我们只不过是要显示字体大小不同的文本而已,也许还要加点边框啥的,我们可以做到每个item只有一个TextView控件。

Spannables

Spannables可以让文本以不同的大小显示,而边框我们可以用drawable解决。这样一来一个item我们就节省了3个view,远比第一种方法要好。

使用Spannables的问题在于time item跟 date item的大号字符个数是不同的。

使用Databinding以及它的BindingAdapters机制,我们可以创建一个属性来设置大号字符的个数。

layout_form_order_step2.xml

   
   
  1. <TextView
  2.     android:id="@+id/txt_time1"
  3.     style="@style/Widget.DateTime"
  4.     app:spanOffset="@{3}"
  5.     />
  6.  
  7. <TextView
  8.     android:id="@+id/txt_date1"
  9.     style="@style/Widget.DateTime"
  10.     app:spanOffset="@{2}"/>

OrderDialogFragment.java

   
   
  1. @BindingAdapter("app:spanOffset")
  2. public static void setItemSpan(View v, int spanOffset) {
  3.     final String itemText = ((TextView) v).getText().toString();
  4.     final SpannableString sString = new SpannableString(itemText);
  5.  
  6.     sString.setSpan(new RelativeSizeSpan(1.75f), itemText.
  7.         length() - spanOffset, itemText.length(),
  8.         Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
  9.  
  10.     ((TextView) v).setText(sString);
  11. }

Scenes(场景)

也许实现下面这个概念的本质是如何实现book按钮和确认视图之间的过渡效果。

如果我们利用好障眼法的话,这也并不难。如果我们不把按钮视作按钮,而是视作一个容器,我们就会意识到可以使用scenes来做到这个动画效果。

整个表单为第一个scene,确认视图则为第二个scene,按钮则是两个界面的共享元素。共享元素就是两个scene之间所共同拥有的一个view,framework将使用一个transition为这个view做恰当的动画。


一旦我们知道逻辑就是改变两个scenes,问题就简单了。

OrderDialogFragment.java

   
   
  1. private void changeToConfirmScene() {
  2.     final LayoutOrderConfirmationBinding confBinding =
  3.         prepareConfirmationBinding();
  4.  
  5.     final Scene scene = new Scene(binding.content,
  6.         ((ViewGroup) confBinding.getRoot()));
  7.  
  8.     scene.setEnterAction(onEnterConfirmScene(confBinding));
  9.  
  10.     final Transition transition = TransitionInflater
  11.         .from(getContext()).inflateTransition(
  12.               R.transition.transition_confirmation_view);
  13.  
  14.     TransitionManager.go(scene, transition);
  15. }

效果

final_result.gif

参考


他们收藏了这篇文章
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值