Native Controls

Background

Despite the fact that views provides facilities for custom layout, rendering and event processing, in many situations we have found it desirable to use the controls provided by the host operating system (Windows to begin with). This is because these widgets already have many desirable properties: a system-native appearance that reflects the latest and greatest of the host operating system (e.g. using the same Win32 API as Windows XP on Windows Vista, native buttons receive glow animations when highlighted), handling for accessibility, focus, etc. Implementing new controls using views and Skia would be possible but it would take a long time to replicate all of this functionality, and we would have to update it for each new operating system release as well. So for areas of our UI where it wasn't important to have a distinctive, custom look, we have fallen back to native controls.

Historic Abstraction

Historically, NativeControls have been used like so:

 
A base class, NativeControl, is the root of all NativeControls, like buttons, checkboxes, tree views, etc. This View subclass is Windows-specific and has a child View that is a HWNDView. This HWNDView hosts a HWND (NativeControlContainer) that is the parent of the actual native control HWND. The parent is responsible for receiving messages sent from the child HWND (e.g. WM_COMMAND, WM_NOTIFY etc) and forwarding these back to the NativeControl. This structure with the additional HWND was thought necessary because the assorted Windows common controls communicate message notifications to the client app by sending messages to the parent window. Back when Chrome had several different ViewContainer/root widget types, it made sense to encapsulate this handling at the NativeControl level. These days, there is only one root HWND type to be concerned with - WidgetWin, so it actually makes more sense to have it receive control notifications and forward them back to the NativeControl, rather than having to carry around all these extra HWNDs.
 
Another problem with this abstraction is related to the fact that Chrome has many different kinds of Buttons. Because NativeButton has no shared base class with the other Button base (BaseButton), much of the API ends up being slightly different. It'd be desirable to share a base class and then implement any of the NativeButton-specific methods in the derived class. However this is not possible due to this structure.
 
A final point of note: some NativeControl subclasses like CheckBox are a combination of system native controls and views components. To get proper transparent rendering behind the text label of a checkbox, the CheckBox has two child views - one which is the native windows control rendering only the checkmark section, and a views::Label child which renders the text. This structure has to be accommodated in any proposed modifications to this design.

Proposed Design

First of all, for any proposed design it's desirable to keep the API simple for users since native controls are used in very many places throughout Chrome. Ideally, using a native control is as simple as constructing one and adding it to your view hierarchy, which is the usage model that exists today for the windows-specific native controls and the views controls.
 
To achieve this, we use the PIMPL idiom to hide the native control implementation from the client in a setup like this:

In this world, NativeButton is a class derived from a base Button class just as the other Button classes are (e.g. TextButton, etc). It overrides various methods that require interaction with the native control, such as making the button appear as the default button in a dialog box etc. The interesting thing here is that the NativeButton itself is cross-platform code. The platform-specific details of implementing a native control are encapsulated behind a platform-neutral NativeControl interface implemented, in this example, by a new class NativeControlWin, a subclass of HWNDView that hosts the actual Windows native control. We avoid having an extra HWND here by stashing a pointer to the NativeControlWin on the attached HWND, and have the message handler in WidgetWin attempt to forward the message to the NativeControlWin directly if it finds such an association. The NativeButton implements a listener interface that receives higher level notifications from the NativeControl implementation about messages received from the operating system.

 
Since NativeControl is an interface not a class, it must provide a GetView accessor for the View that is to be parented as a child of the NativeButton, CheckBox or other view.
 
In this way, NativeButton can share a base class with other button types. A similar relationship can exist for other native controls where this is applicable, e.g. scroll bars, tree views, etc.

More Complex Controls

For controls more complex than buttons like, for example, TreeViews, there can be more elaborate code in NativeControlWin subclasses that handle messages from the native UI control and notify the view on the right half of the diagram as needed. Keeping the views on the right half of diagram platform neutral hides the complexity of maintaining platform-specific controls from consumers in the application - e.g. there is no need for ifdefs or factory methods at the call sites - the views can just be constructed directly and added to the view hierarchy:
 
void FooView::Init() {
  button_ = new views::NativeButton;
  button_->SetListener(this);
  AddChildView(button_);
}
 
...
 
void FooView::Layout() {
  button_->SetBounds(0, 0, width(), height());
}
 
vs the more baroque:
 
void FooView::Init() {
  button_ = views::NativeButton::CreateNativeButton();
  button_->SetListener(this);
  AddChildView(button_->GetView());
}
 
...
 
void FooView::Layout() {
  button_->GetView()->Layout(0, 0, width(), height());
}

UI Framework-1: Native Controls的更多相关文章

  1. Hybrid UI framework shootout: Ionic vs. Famo.us vs. F7 vs. OnsenUI

    1 Introduction In the past 2 years I’ve been working intensively on mobile applications, mostly hybr ...

  2. 00 - Vue3 UI Framework - 阅读辅助列表

    阅读列表 01 - Vue3 UI Framework - 开始 02 - Vue3 UI Framework - 顶部边栏 03 - Vue3 UI Framework - 首页 04 - Vue3 ...

  3. [转]Ionic – Mobile UI Framework for PhoneGap/Cordova Developers

    本文转自:http://devgirl.org/2014/01/20/ionic-mobile-ui-framework-for-phonegapcordova-developers/ Ionic i ...

  4. 05 - Vue3 UI Framework - Button 组件

    官网基本做好了,接下来开始做核心组件 返回阅读列表点击 这里 目录准备 在项目 src 目录下创建 lib 文件夹,用来存放所有的核心组件吧.然后再在 lib 文件夹下创建 Button.vue 文件 ...

  5. 01 - Vue3 UI Framework - 开始

    写在前面 一年多没写过博客了,工作.生活逐渐磨平了棱角. 写代码容易,写博客难,坚持写高水平的技术博客更难. 技术控决定慢慢拾起这份坚持,用作技术学习的阶段性总结. 返回阅读列表点击 这里 开始 大前 ...

  6. 03 - Vue3 UI Framework - 首页

    顶部边栏做完了,接下来开始做官网的首页 返回阅读列表点击 这里 创建视图文件夹 让我们先新建一个 src/views 文件夹,用来存放官网的主要视图 然后在该文件夹下新建两个 vue 文件,作为我们的 ...

  7. 07- Vue3 UI Framework - Switch 组件

    为了更好的提升用户体验,我们这里再做一个很常用的开关组件 switch 返回阅读列表点击 这里 需求分析 开始之前我们先做一个简单的需求分析 switch 组件应分为选中/未被选中,两种状态 可以通过 ...

  8. 08 - Vue3 UI Framework - Input 组件

    接下来再做一个常用的组件 - input 组件 返回阅读列表点击 这里 需求分析 开始之前我们先做一个简单的需求分析 input 组件有两种类型,即 input 和 textarea 类型 当类型为 ...

  9. 09 - Vue3 UI Framework - Table 组件

    接下来做个自定义的表格组件,即 table 组件 返回阅读列表点击 这里 需求分析 开始之前我们先做一个简单的需求分析 基于原生 table 标签的强语义 允许用户自定义表头.表体 可选是否具有边框 ...

随机推荐

  1. 火狐访问IIS出现404,而Chrome可以正常访问

    需要在web.config中的handlers中添加如下节点,保存之后,需要重启电脑. <remove name="ExtensionlessUrlHandler-Integrated ...

  2. RSA in .net and dotnet core

    dotnet RSAParameters Struct https://docs.microsoft.com/zh-cn/dotnet/api/system.security.cryptography ...

  3. hihocoder 1407 重复旋律2

    思路: 二分一哈答案 height分个块 //By SiriusRen #include <cstdio> #include <cstring> #include <al ...

  4. C++提高速度

  5. Windows 10 10586 升级

  6. php 添加redis扩展

    我主要是按照http://blog.163.com/fan_xy_qingyuan/blog/static/1889877482014111111283265/ 这篇博客来的,但是这篇博客里只有php ...

  7. swift中高阶函数map、flatMap、filter、reduce

    Swift相比于Objective-C又一个重要的优点,它对函数式编程提供了很好的支持,Swift提供了map.filter.reduce这三个高阶函数作为对容器的支持. 1 map:可以对数组中的每 ...

  8. swift语言点评十六-Initialization && Deinitialization

    initial value:必须初始化.不影响观察者 Classes and structures must set all of their stored properties to an appr ...

  9. 洛谷P1231 教辅的组成 网络流

    Code: #include<cstdio> #include<cstring> #include<algorithm> #include<vector> ...

  10. 洛谷P1494 [国家集训队]小Z的袜子

    Code: #include<cstdio> #include<iostream> #include<algorithm> #include<cstring& ...