Harry Hsu
林宇軒
Calvin Huang
終於讓我有機會做這件事了
這是我家貓咪
名字是黑妞,可愛的男孩子 ♂
神代的人類語言統一
創造了無數輝煌
人們建造了巴別塔嘗試達到神的境界而被懲罰
混亂的語言讓世界不再統一
無法再創過往的榮耀
Credit: https://www.learnui.design/blog/ios-vs-android-app-ui-design-complete-guide.html
struct LoginView: View {
@StateObject var viewModel = LoginViewModel()
var body: some View {
VStack {
Image("STREAMMARK")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(height: 40)
.padding(.all, 24)
Text("Welcome to Stream Chat")
.font(.title)
.padding(.all, 8)
Text("Select a user to try the iOS SDK:")
.font(.body)
.padding(.all, 8)
.padding(.bottom, 16)
List(viewModel.demoUsers) { user in
Button {
viewModel.demoUserTapped(user)
} label: {
DemoUserView(user: user)
}
.padding(.vertical, 4)
.animation(nil)
}
.listStyle(.plain)
Spacer()
}
.overlay(
viewModel.loading ? ProgressView() : nil
)
}
}
@Composable
private fun LoginScreen() {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Spacer(modifier = Modifier.height(32.dp))
Icon(
modifier = Modifier.size(width = 80.dp, height = 40.dp),
painter = painterResource(id = R.drawable.ic_stream),
contentDescription = null,
tint = ChatTheme.colors.primaryAccent,
)
Spacer(modifier = Modifier.height(28.dp))
Text(
modifier = Modifier.padding(horizontal = 16.dp),
text = stringResource(R.string.login_screen_title),
fontSize = 22.sp,
fontWeight = FontWeight.Bold,
color = ChatTheme.colors.textHighEmphasis,
)
Spacer(modifier = Modifier.height(12.dp))
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.weight(1f),
) {
items(items = LoginUsers.createUsers()) { loginUser ->
UserItem(loginUser = loginUser)
DividerItem()
}
}
}
}
struct LoginView: View {
@StateObject var viewModel = LoginViewModel()
var body: some View {
VStack {
Image("STREAMMARK")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(height: 40)
.padding(.all, 24)
Text("Welcome to Stream Chat")
.font(.title)
.padding(.all, 8)
Text("Select a user to try the iOS SDK:")
.font(.body)
.padding(.all, 8)
.padding(.bottom, 16)
List(viewModel.demoUsers) { user in
Button {
viewModel.demoUserTapped(user)
} label: {
DemoUserView(user: user)
}
.padding(.vertical, 4)
.animation(nil)
}
.listStyle(.plain)
Spacer()
}
.overlay(
viewModel.loading ? ProgressView() : nil
)
}
}
@Composable
private fun LoginScreen() {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Spacer(modifier = Modifier.height(32.dp))
Icon(
modifier = Modifier.size(width = 80.dp, height = 40.dp),
painter = painterResource(id = R.drawable.ic_stream),
contentDescription = null,
tint = ChatTheme.colors.primaryAccent,
)
Spacer(modifier = Modifier.height(28.dp))
Text(
modifier = Modifier.padding(horizontal = 16.dp),
text = stringResource(R.string.login_screen_title),
fontSize = 22.sp,
fontWeight = FontWeight.Bold,
color = ChatTheme.colors.textHighEmphasis,
)
Spacer(modifier = Modifier.height(12.dp))
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.weight(1f),
) {
items(items = LoginUsers.createUsers()) { loginUser ->
UserItem(loginUser = loginUser)
DividerItem()
}
}
}
}
同場加映 - React???
mport React, { useState, useEffect } from 'react';
const LoginView = () => {
const [viewModel, setViewModel] = useState(new LoginViewModel());
const [loading, setLoading] = useState(viewModel.loading);
useEffect(() => {
// Assuming you have a way to update loading status in your view model
const handleLoadingChange = () => setLoading(viewModel.loading);
viewModel.onLoadingChange = handleLoadingChange;
return () => {
viewModel.onLoadingChange = null;
};
}, [viewModel]);
return (
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
<img
src="path_to_STREAMMARK_image"
style={{ height: '40px', aspectRatio: 'fit', padding: '24px' }}
alt="STREAMMARK"
/>
<h1 style={{ padding: '8px' }}>Welcome to Stream Chat</h1>
<p style={{ padding: '8px', paddingBottom: '16px' }}>Select a user to try the iOS SDK:</p>
<div style={{ width: '100%' }}>
{viewModel.demoUsers.map(user => (
<button key={user.id} onClick={() => viewModel.demoUserTapped(user)} style={{ padding: '4px', width: '100%', textAlign: 'left' }}>
<DemoUserView user={user} />
</button>
))}
</div>
{loading && <p>Loading...</p>}
</div>
);
};
export default LoginView;
MVP
MVVM
MVI
✅
✅
✅
✅
✅
✅
The Dart code that paints Flutter’s visuals is compiled into native code, which uses Skia (or, in future, Impeller) for rendering.
Let's take a brief dive into the mechanism
the React Native renderer communicates with the host platform to mount host views on the screen (create, insert, update or delete of host views) and it listens for events that are generated by the user on the host platform.
Let's take a brief dive into the mechanism
This is the most common scenario where most of the render pipeline happens on JavaScript thread.
Be cautious of ReactNative performance
For most React Native applications, your business logic will run on the JavaScript thread.
...
Any animations controlled by JavaScript would appear to freeze during that time. If anything takes longer than 100ms, the user will feel it.
It's better in Flutter
FPS:
At the very least, don't let it bother you too much.
Ultimately, it doesn't really matter. 60FPS works well for everyone, and most people won't notice if you drop a few frames here and there... except maybe for professional gamers
Both Flutter and ReactNative
If you want it to appear like a native app, you'll need to create that effect on your own.
Of course the original UI experiences...?
Flutter does the awesome effort to save your time
Both Flutter and ReactNative
And it still some issues, though
Native Implementation
Shared Module
這時候又需要將外包的 code 接回來繼續做下去怎麼辦!?
Shared module
5%
...haha
Provide a cross-platform UI solution
Built the app on top on of that
Try to figure out the all common behaviors and adapt them to shared module
Get limited since all build on top of fundation UI framework
Provide a way to share the logic (perhaps data)
Extract common logic across projects
Discuss if anything else needs to be placed at shared module
Feel free to leave or stay whenever you want
Provide a cross-platform UI solution
Built the app on top on of that
Try to figure out the all common behaviors and adapt them to shared module
Get limited since all build on top of fundation UI framework
因為 UI 用跨平台方案
讀不同平台的文件,找出 API 共同的行為
根據跨平台方案的接口整合
Provide a way to share the logic (perhaps data)
Extract common logic across projects
Discuss if anything else needs to be placed at shared module
Feel free to leave or stay whenever you want
基於不同平台分別實作
討論是不是要將相似的接口整合進 shared module
- 交換完全 native,
- 實作接口,讓 shared-
流程後拋回 UI 連動處理
module 處理交換
因為 UI 用跨平台方案
讀不同平台的文件,找出 API 共同的行為
根據跨平台方案的接口整合
基於不同平台分別實作
討論是不是要將相似的接口整合進 shared module
- 交換完全 native,
- 實作接口,讓 shared-
流程後拋回 UI 連動處理
module 處理交換
Kotlin Multiplatofm is stable
QA time
https://app.sli.do/event/aSqr53HcJnCNPacBdvCCGa
Recurting
https://www.cakeresume.com/companies/i-pass