QMUILayout, 让 UI 开发更简单

简介: 在 Android UI开发过程中,我们会觉得非常繁琐的事情是什么呢?分隔线、圆角、边框、阴影、点击态等,在以往的实践中,我们都是通过 drawable 去实现的,非常麻烦。以分隔线为例,如果左右都打通,那还能复用,但现在的设计师都喜欢左边或右边有一定的 inset,而 inset 的值并非一成不变的,这不经意间就使得项目添加了数不清的 drawable,因此目前大多数人都开始尝试不使用 drawble 去解决这些问题了,QMUI 也不例外。

在 Android UI开发过程中,我们会觉得非常繁琐的事情是什么呢?分隔线、圆角、边框、阴影、点击态等,在以往的实践中,我们都是通过 drawable 去实现的,非常麻烦。以分隔线为例,如果左右都打通,那还能复用,但现在的设计师都喜欢左边或右边有一定的 inset,而 inset 的值并非一成不变的,这不经意间就使得项目添加了数不清的 drawable,因此目前大多数人都开始尝试不使用 drawble 去解决这些问题了,QMUI 也不例外。


QMUI 1.1.0 版本带来的新的组件套装 QMUILayout (QMUILinearLayout、QMUIRelativeLayout、QMUIFramelayout),这篇文章将介绍 QMUI 提出的解决方法。

点击态


点击态最为简单,QMUI 早已经提出用 alpha 来表示点击态,因此提供了了 QMUIAlpha 系列,QMUILayout 继承自 QMUIAlpha 系列,但默认禁止了 alpha 行为, 你可以通过以下两个方法开启:

// change alpha when pressed
setChangeAlphaWhenPress(boolean changeAlphaWhenPress);
// change alpha when disabled
setChangeAlphaWhenDisable(boolean changeAlphaWhenDisable)  

当然,点击时背景变灰也是非常常见的。qmui 最开始提供了一系列的用于 list item 的 drawable, 现在我们基本只需要 qmui_s_list_item_bg_with_border_none, 因为现在分割线不再受背景控制了。

分隔线


分隔线是平常使用得非常多的,上下分隔下用的较多,左右分隔线用得比较少,QMUILayout 都提供了 xml 和 java 代码的支持:

<declare-styleable name="QMUILayout">  
    ...
    <attr name="qmui_bottomDividerHeight" format="dimension"/>
    <attr name="qmui_bottomDividerColor" format="color|reference"/>
     <attr name="qmui_bottomDividerInsetLeft" format="dimension"/>
     <attr name="qmui_bottomDividerInsetRight" format="dimension"/>
     <attr name="qmui_topDividerHeight" format="dimension"/>
     <attr name="qmui_topDividerColor" format="color|reference"/>
    <attr name="qmui_topDividerInsetLeft" format="dimension"/>
    <attr name="qmui_topDividerInsetRight" format="dimension"/>
    <attr name="qmui_leftDividerWidth" format="dimension"/>
    <attr name="qmui_leftDividerColor" format="color|reference"/>
    <attr name="qmui_leftDividerInsetTop" format="dimension"/>
    <attr name="qmui_leftDividerInsetBottom" format="dimension"/>
    <attr name="qmui_rightDividerWidth" format="dimension"/>
    <attr name="qmui_rightDividerColor" format="color|reference"/>
    <attr name="qmui_rightDividerInsetTop" format="dimension"/>
    <attr name="qmui_rightDividerInsetBottom" format="dimension"/>
    ...
</declare-styleable>  

四个维度的支持,使用非常方便, java 接口:

/**
 * config the top divider
 */
void updateTopDivider(int topInsetLeft, int topInsetRight, int topDividerHeight, int topDividerColor);
/**
 * show top divider, and hide others
 */
void onlyShowTopDivider(int topInsetLeft, int topInsetRight, int topDividerHeight, int topDividerColor);
// same for others

其实现原理也很简单,就是在 dispatchDraw 里主动 draw 上去的,那我们为什么是在 dispatchDraw 而不是在 onDraw 里操作呢? 因为我们不想分隔线被子元素、背景等因素遮挡。

阴影、圆角、边框


这是 QMUILayout 最令人兴奋的地方,大家可以在 QMUIDemo 上体验下效果:

其实原理很简单,利用 android 5.0 后提供的 elevation 来实现的, 大多数人通过阅读官方文档或者别人的教材,了解了 elevation 可以控制 shadow 的大小,但是很少人知道 shadow 还会被另外一个因素所控制:outline 的 alpha。 有了这两个因素,可以更精确的控制 shadow 的深浅,能无限接近设计师的阴影要求,当然,除了阴影颜色,那是 QMUILayout 所不能控制的。


利用 outline 还可以用来实现圆角,以前我们用背景去实现圆角效果,但你需要非常小心的保护圆角背景不被子元素所覆盖,但 outline 不会有这个问题。outline 如此强大,如果还不知道它,那么赶紧去通过View.setOutlineProvider() 了解一下它吧。


但 outline 也有缺陷的,它没办法做到四个圆角分别控制,现实使用过程中,有一个圆角或三个圆角的情况比较少,所以我在 QMUILayout 中支持了 显示两个圆角的方法,但可惜的是会丢失阴影,现实总是不尽人意,尽自己最大努力就好。


另外一个比较关心的话题是, 4.x的手机怎么办?网页重构早就讲究降级兼容,所以我也认为没有必要让 4.x 和 5.x+ 保持同样的用户体验。因此在 4.x 下,阴影肯定是没办法使用的,只能使用圆角和边框,要使用它们,我们需要提供一个额外的参数: qmui_outerNormalColor, 这个参数是什么意思呢?这首先要理解圆角在 4.x 上的实现: 它的实现是在 dispatchDraw 后,draw 上一层 mask, 然后镂空中间部分,因此 qmui_outerNormalColor            就是 mask 的颜色,一般要与 QMUILayout 外部环境相同, 这样在用户眼中,看到的就是圆角了。如果你没有提供这个属性,那么圆角将不会生效。此外,它也无法解决 dialog 这种外部环境透明的场景。


接下来看看提供的非常有用的 API:

/**
 * use the shadow elevation from the theme
 */
void setUseThemeGeneralShadowElevation();  
/**
 * See {@link android.view.View#setElevation(float)}
 *
 * @param elevation
 */
void setShadowElevation(int elevation);
/**
 * See {@link View#getElevation()}
 *
 * @return
 */
int getShadowElevation();
/**
 * set the outline alpha, which will change the shadow
 *
 * @param shadowAlpha
 */
void setShadowAlpha(float shadowAlpha);
/**
 * get the outline alpha we set
 *
 * @return
 */
float getShadowAlpha();
/**
 * set the layout radius
 * @param radius
 */
void setRadius(int radius);
/**
 * set the layout radius with one or none side been hidden
 * @param radius
 * @param hideRadiusSide
 */
void setRadius(int radius, @QMUILayoutHelper.HideRadiusSide int hideRadiusSide);
/**
 * get the layout r
 * @return
 */
int getRadius();  
/**
 * the shadow elevation only work after L, so we provide a downgrading compatible solutions for android 4.x
 * usually we use border, but the border may be redundant for android L+. so will not show border default,
 * if your designer like the border exists with shadow, you can call setShowBorderOnlyBeforeL(false)
 *
 * @param showBorderOnlyBeforeL
 */
void setShowBorderOnlyBeforeL(boolean showBorderOnlyBeforeL);
/**
 * in some case, we maybe hope the layout only have radius in one side.
 * but there is no convenient way to write the code like canvas.drawPath,
 * so we take another way that hide one radius side
 *
 * @param hideRadiusSide
 */
void setHideRadiusSide(@HideRadiusSide int hideRadiusSide);
/**
 * get the side that we have hidden the radius
 *
 * @return
 */
int getHideRadiusSide();
/**
 * this method will determine the radius and shadow.
 *
 * @param radius
 * @param shadowElevation
 * @param shadowAlpha
 */
void setRadiusAndShadow(int radius, int shadowElevation, float shadowAlpha);
/**
 * this method will determine the radius and shadow with one or none side be hidden
 *
 * @param radius
 * @param hideRadiusSide
 * @param shadowElevation
 * @param shadowAlpha
 */
void setRadiusAndShadow(int radius, @HideRadiusSide int hideRadiusSide, int shadowElevation, float shadowAlpha);
/**
 * border color, if you don not set it, the layout will not draw the border
 *
 * @param borderColor
 */
void setBorderColor(@ColorInt int borderColor);
/**
 * border width, default is 1px, usually no need to set
 *
 * @param borderWidth
 */
void setBorderWidth(int borderWidth);  

QMUILayout 所有的 API 都由 IQMUILayout 所规范, 由 QMUILayoutHelper 所实现,如果你需要为自己的自定义 view 实现这些方法, 那么你可以在你的类中引入 QMUILayoutHelper,具体可以参考 QMUILinearLayout/QMUIFrameLayout/QMUIRelativeLayout


最后一点,关于性能,View.setOutlineProvider() 会存在性能消耗,不过就我们的测试数据统计,这点消耗是可以容忍的。目前 QMUILayout 已经为读书项目服务了几个版本了,稳定性应该是蛮好的,希望大家喜欢。

目录
相关文章
|
2月前
|
前端开发 编解码 数据格式
浅谈响应式编程在企业级前端应用 UI 开发中的实践
浅谈响应式编程在企业级前端应用 UI 开发中的实践
浅谈响应式编程在企业级前端应用 UI 开发中的实践
|
9月前
|
设计模式 测试技术 vr&ar
提升你的Android开发技能:从AR/VR沉浸到UI设计和故障排除(三)
提升你的Android开发技能:从AR/VR沉浸到UI设计和故障排除
|
9月前
|
人工智能 机器人 区块链
提升你的Android开发技能:从AR/VR沉浸到UI设计和故障排除(二)
提升你的Android开发技能:从AR/VR沉浸到UI设计和故障排除
|
2月前
|
Android开发 缓存 双11
android的基础ui组件,Android开发社招面试经验
android的基础ui组件,Android开发社招面试经验
android的基础ui组件,Android开发社招面试经验
|
5天前
|
机器学习/深度学习 移动开发 文字识别
视觉智能开放平台产品使用合集之h5页面使用人脸活体检测,是否需要自己开发UI
视觉智能开放平台是指提供一系列基于视觉识别技术的API和服务的平台,这些服务通常包括图像识别、人脸识别、物体检测、文字识别、场景理解等。企业或开发者可以通过调用这些API,快速将视觉智能功能集成到自己的应用或服务中,而无需从零开始研发相关算法和技术。以下是一些常见的视觉智能开放平台产品及其应用场景的概览。
|
2月前
|
JavaScript API
鸿蒙开发接口UI界面:【@ohos.mediaquery (媒体查询)】
鸿蒙开发接口UI界面:【@ohos.mediaquery (媒体查询)】
29 1
|
2月前
UI开发第四篇——实现像handcent sms或者chomp sms那样的气泡
UI开发第四篇——实现像handcent sms或者chomp sms那样的气泡
18 2
|
2月前
|
Android开发 开发者 UED
探索安卓应用开发中的UI设计趋势
随着移动应用市场的不断发展和用户需求的变化,安卓应用的UI设计趋势也在不断演进。本文将深入探讨当前安卓应用开发中的UI设计趋势,包括暗黑模式、原生化设计、动效设计等方面的发展趋势,为开发者提供参考和启发。
|
2月前
|
开发框架 前端开发 JavaScript
【Flutter前端技术开发专栏】Flutter中的动态UI构建与数据驱动视图
【4月更文挑战第30天】Flutter是一款高效跨平台移动开发框架,以其热重载、高性能渲染和丰富组件库著称,简化了动态UI和数据驱动视图的实现。本文深入讨论了动态UI构建原理,包括基于Widget树模型的UI更新和状态管理,如使用StatefulWidget和数据流库(如Provider、Redux)。此外,文中还介绍了实现技巧,如使用ListView等可滚动组件、StreamBuilder进行数据流驱动的UI更新,以及应用响应式布局以适应不同设备。Flutter为开发者提供了构建高效动态界面的强大工具。
【Flutter前端技术开发专栏】Flutter中的动态UI构建与数据驱动视图
|
2月前
|
前端开发 测试技术 持续交付
【Flutter 前端技术开发专栏】Flutter 中的 UI 测试与自动化测试
【4月更文挑战第30天】本文探讨了 Flutter 应用中UI测试和自动化测试的重要性,包括保障质量、提高效率和增强开发信心。Flutter提供`flutter_test`库进行Widget测试,以及`flutter_driver`进行集成测试。UI测试涵盖界面布局、交互和状态变化的验证,最佳实践建议尽早引入测试、保持用例简洁,并结合手动测试。未来,随着Flutter技术发展,UI测试和自动化测试将更加完善,助力开发高质量应用。
【Flutter 前端技术开发专栏】Flutter 中的 UI 测试与自动化测试