Upgrade to Pro — share decks privately, control downloads, hide ads and more …

iOS、Android、Flutter超級比一比

MarkFly
November 08, 2020
930

 iOS、Android、Flutter超級比一比

#iPlayground2020

以iOS Developer的角度去介紹與比較Android和Flutter
搭配程式碼跟Demo並佐以採坑實錄
用最入門與淺顯易懂的說明
讓聽眾可以在很短的時間內
對另外兩個平台的開發有一定瞭解

錄影:https://www.youtube.com/watch?v=g-jvBrLMOqA

MarkFly

November 08, 2020
Tweet

Transcript

  1. 謝騰⾶(MarkFly) Sr. iOS Developer Jr. Flutter 愛好者 About me •

    ⽤Cocos2d寫遊戲 • ⾊⾊的直播(不是Swag) • iT 邦幫忙鐵⼈賽連續兩年完賽 • ⽤Swift控制遙控⾞ • 線上下棋App • ⿇布記帳 mark33699 MarkFlyyyyy
  2. 基 本 資 料 iOS Cross Platform Android Swift /

    Objective-C Dart Kotlin / Java Xcode / AppCode Android Studio /
 Visual Studio Code Android Studio /
 IntelliJ IDEA Imperative style Declarative style Imperative style
  3. UI 元 件 UILabel Text TextView UITextField TextField EditText UITableView

    ListView RecycleView UICollectionView GridView RecycleView
  4. 畫 ⾯ ⽣ 命 週 期 init createState viewDidLoad initState

    onCreate viewWillAppear onStart viewDidLayoutSubviews build viewDidAppear onResume
  5. 畫 ⾯ ⽣ 命 週 期 viewWillDisappear onPause viewDidDisappear onStop

    removeFromSuperview deactivate deinit dispose onDestroy
  6. Cordova 微信⼩程序 React Native Xamarin Flutter HTML 5 HTML 5

    Java Script C# Dart Apache 騰訊 Facebook Microsoft Google 全動態化 全動態化 全動態化 全動態化 半動態化 跨 平 台 技 術 本⾴資料整理⾃:《Flutter实战》1.1 移动开发技术简介 WebView 原⽣元件 ⾃繪UI
  7. <?xml version="1.0" encoding="utf-8"?> <androidx.cardview.widget.CardView 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="wrap_content" android:layout_marginTop="8dp"

    android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:layout_marginBottom="4dp" app:cardCornerRadius="8dp" app:cardElevation="4dp"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/imageView_avatar" android:layout_width="60dp" android:layout_height="0dp" android:layout_marginStart="8dp" android:layout_marginTop="10dp" android:layout_marginBottom="10dp" android:background="#673AB7" android:contentDescription="@string/avatar" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintDimensionRatio="1" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:srcCompat="@tools:sample/avatars" /> <TextView android:id="@+id/textView_userName" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginEnd="8dp" android:textSize="20sp" app:layout_constraintBottom_toTopOf="@+id/textView_userMail" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toEndOf="@+id/imageView_avatar" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_chainStyle="packed" /> <TextView android:id="@+id/textView_userMail" android:layout_width="0dp" android:layout_height="wrap_content" android:textSize="16sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="@+id/textView_userName" app:layout_constraintStart_toStartOf="@+id/textView_userName" app:layout_constraintTop_toBottomOf="@+id/textView_userName" /> </androidx.constraintlayout.widget.ConstraintLayout> </androidx.cardview.widget.CardView>
  8. <?xml version="1.0" encoding="UTF-8"?> <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17156" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES"

    useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> <device id="retina6_1" orientation="portrait" appearance="light"/> <dependencies> <deployment identifier="iOS"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17126"/> <capability name="Safe area layout guides" minToolsVersion="9.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> </dependencies> <objects> <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="80" id="KGk-i7-Jjw" customClass="UserTableViewCell" customModule="iPG_20" customModuleProvider="target"> <rect key="frame" x="0.0" y="0.0" width="320" height="80"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM"> <rect key="frame" x="0.0" y="0.0" width="320" height="80"/> <autoresizingMask key="autoresizingMask"/> <subviews> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="mIo-Ks-s0J"> <rect key="frame" x="4" y="4" width="312" height="72"/> <subviews> <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="inf-PY-EjT"> <rect key="frame" x="8" y="6" width="60" height="60"/> <constraints> <constraint firstAttribute="width" constant="60" id="6S9-5H-Wzd"/> <constraint firstAttribute="height" constant="60" id="c5S-jV-eBK"/> </constraints> </imageView> <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" spacing="4" translatesAutoresizingMaskIntoConstraints="NO" id="QaJ-je-Ht1"> <rect key="frame" x="76" y="8" width="228" height="56"/> <subviews> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="QCy-3v-Vdb"> <rect key="frame" x="0.0" y="0.0" width="228" height="26"/> <fontDescription key="fontDescription" type="system" pointSize="17"/> <nil key="textColor"/> <nil key="highlightedColor"/> </label> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ErJ-AB-lic"> <rect key="frame" x="0.0" y="30" width="228" height="26"/> <fontDescription key="fontDescription" type="system" pointSize="17"/> <nil key="textColor"/> <nil key="highlightedColor"/> </label> </subviews> </stackView> </subviews> <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <constraints> <constraint firstAttribute="trailing" secondItem="QaJ-je-Ht1" secondAttribute="trailing" constant="8" id="WFN-xg-CUz"/> <constraint firstItem="QaJ-je-Ht1" firstAttribute="leading" secondItem="inf-PY-EjT" secondAttribute="trailing" constant="8" id="bYB-jg-SE3"/> <constraint firstItem="inf-PY-EjT" firstAttribute="leading" secondItem="mIo-Ks-s0J" secondAttribute="leading" constant="8" id="cTj-Ip-Z8K"/> <constraint firstAttribute="bottom" secondItem="QaJ-je-Ht1" secondAttribute="bottom" constant="8" id="mgI-fu-ltD"/> <constraint firstItem="QaJ-je-Ht1" firstAttribute="centerY" secondItem="inf-PY-EjT" secondAttribute="centerY" id="qOv-Re-0lQ"/> <constraint firstItem="QaJ-je-Ht1" firstAttribute="top" secondItem="mIo-Ks-s0J" secondAttribute="top" constant="8" id="sjT-kR-TUV"/> <constraint firstItem="inf-PY-EjT" firstAttribute="centerY" secondItem="mIo-Ks-s0J" secondAttribute="centerY" id="zxF-TC-SMw"/> </constraints> <userDefinedRuntimeAttributes> <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius"> <real key="value" value="8"/> </userDefinedRuntimeAttribute> <userDefinedRuntimeAttribute type="size" keyPath="layer.shadowOffset"> <size key="value" width="0.0" height="2"/> </userDefinedRuntimeAttribute> <userDefinedRuntimeAttribute type="number" keyPath="layer.shadowRadius"> <integer key="value" value="1"/> </userDefinedRuntimeAttribute> <userDefinedRuntimeAttribute type="number" keyPath="layer.shadowOpacity"> <integer key="value" value="1"/> </userDefinedRuntimeAttribute> </userDefinedRuntimeAttributes> </view> </subviews> <constraints> <constraint firstAttribute="bottom" secondItem="mIo-Ks-s0J" secondAttribute="bottom" constant="4" id="4So-rx-Ztk"/> <constraint firstAttribute="trailing" secondItem="mIo-Ks-s0J" secondAttribute="trailing" constant="4" id="CPW-34-Kie"/> <constraint firstItem="mIo-Ks-s0J" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" constant="4" id="PWr-nz-cKc"/> <constraint firstItem="mIo-Ks-s0J" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="4" id="flo-rq-t2P"/> </constraints> </tableViewCellContentView> <viewLayoutGuide key="safeArea" id="njF-e1-oar"/> <point key="canvasLocation" x="-13.043478260869566" y="103.79464285714285"/> </tableViewCell> </objects> </document>
  9. return Card( child: ListTile( leading: Container( constraints: BoxConstraints(minWidth: 60, minHeight:

    60), color: Colors.black38, child: Image.network(user.avatar, fit: BoxFit.fill), ), title: Text("${user.firstName} ${user.lastName}"), subtitle: Text(user.email), ) );
  10. // Imperative style b.setColor(red) b.clearChildren() ViewC c3 = new ViewC(...)

    b.add(c3) // Declarative style return ViewB( color: red, child: ViewC(...), )
  11. class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) {

    super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } }
  12. <?xml version="1.0" encoding="utf-8"?> <androidx.cardview.widget.CardView 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="wrap_content" android:layout_marginTop="8dp"

    android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:layout_marginBottom="4dp" app:cardCornerRadius="8dp" app:cardElevation="4dp"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/imageView_avatar" android:layout_width="60dp" android:layout_height="0dp" android:layout_marginStart="8dp" android:layout_marginTop="10dp" android:layout_marginBottom="10dp" android:background="#673AB7" android:contentDescription="@string/avatar" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintDimensionRatio="1" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:srcCompat="@tools:sample/avatars" /> <TextView android:id="@+id/textView_userName" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginEnd="8dp" android:textSize="20sp" app:layout_constraintBottom_toTopOf="@+id/textView_userMail" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toEndOf="@+id/imageView_avatar" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_chainStyle="packed" /> <TextView android:id="@+id/textView_userMail" android:layout_width="0dp" android:layout_height="wrap_content" android:textSize="16sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="@+id/textView_userName" app:layout_constraintStart_toStartOf="@+id/textView_userName" app:layout_constraintTop_toBottomOf="@+id/textView_userName" /> </androidx.constraintlayout.widget.ConstraintLayout> </androidx.cardview.widget.CardView> <androidx.cardview.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:layout_marginBottom="4dp" app:cardCornerRadius="8dp" app:cardElevation="4dp"> </androidx.cardview.widget.CardView>
  13. <?xml version="1.0" encoding="utf-8"?> <androidx.cardview.widget.CardView 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="wrap_content" android:layout_marginTop="8dp"

    android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:layout_marginBottom="4dp" app:cardCornerRadius="8dp" app:cardElevation="4dp"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/imageView_avatar" android:layout_width="60dp" android:layout_height="0dp" android:layout_marginStart="8dp" android:layout_marginTop="10dp" android:layout_marginBottom="10dp" android:background="#673AB7" android:contentDescription="@string/avatar" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintDimensionRatio="1" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:srcCompat="@tools:sample/avatars" /> <TextView android:id="@+id/textView_userName" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginEnd="8dp" android:textSize="20sp" app:layout_constraintBottom_toTopOf="@+id/textView_userMail" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toEndOf="@+id/imageView_avatar" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_chainStyle="packed" /> <TextView android:id="@+id/textView_userMail" android:layout_width="0dp" android:layout_height="wrap_content" android:textSize="16sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="@+id/textView_userName" app:layout_constraintStart_toStartOf="@+id/textView_userName" app:layout_constraintTop_toBottomOf="@+id/textView_userName" /> </androidx.constraintlayout.widget.ConstraintLayout> </androidx.cardview.widget.CardView> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> </androidx.constraintlayout.widget.ConstraintLayout>
  14. <?xml version="1.0" encoding="utf-8"?> <androidx.cardview.widget.CardView 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="wrap_content" android:layout_marginTop="8dp"

    android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:layout_marginBottom="4dp" app:cardCornerRadius="8dp" app:cardElevation="4dp"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/imageView_avatar" android:layout_width="60dp" android:layout_height="0dp" android:layout_marginStart="8dp" android:layout_marginTop="10dp" android:layout_marginBottom="10dp" android:background="#673AB7" android:contentDescription="@string/avatar" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintDimensionRatio="1" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:srcCompat="@tools:sample/avatars" /> <TextView android:id="@+id/textView_userName" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginEnd="8dp" android:textSize="20sp" app:layout_constraintBottom_toTopOf="@+id/textView_userMail" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toEndOf="@+id/imageView_avatar" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_chainStyle="packed" /> <TextView android:id="@+id/textView_userMail" android:layout_width="0dp" android:layout_height="wrap_content" android:textSize="16sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="@+id/textView_userName" app:layout_constraintStart_toStartOf="@+id/textView_userName" app:layout_constraintTop_toBottomOf="@+id/textView_userName" /> </androidx.constraintlayout.widget.ConstraintLayout> </androidx.cardview.widget.CardView> <ImageView android:id="@+id/imageView_avatar" android:layout_width="60dp" android:layout_height="0dp" android:layout_marginStart="8dp" android:layout_marginTop="10dp" android:layout_marginBottom="10dp" android:background="#673AB7" android:contentDescription="@string/avatar" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintDimensionRatio="1" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:srcCompat="@tools:sample/avatars" />
  15. <?xml version="1.0" encoding="utf-8"?> <androidx.cardview.widget.CardView 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="wrap_content" android:layout_marginTop="8dp"

    android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:layout_marginBottom="4dp" app:cardCornerRadius="8dp" app:cardElevation="4dp"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/imageView_avatar" android:layout_width="60dp" android:layout_height="0dp" android:layout_marginStart="8dp" android:layout_marginTop="10dp" android:layout_marginBottom="10dp" android:background="#673AB7" android:contentDescription="@string/avatar" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintDimensionRatio="1" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:srcCompat="@tools:sample/avatars" /> <TextView android:id="@+id/textView_userName" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginEnd="8dp" android:textSize="20sp" app:layout_constraintBottom_toTopOf="@+id/textView_userMail" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toEndOf="@+id/imageView_avatar" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_chainStyle="packed" /> <TextView android:id="@+id/textView_userMail" android:layout_width="0dp" android:layout_height="wrap_content" android:textSize="16sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="@+id/textView_userName" app:layout_constraintStart_toStartOf="@+id/textView_userName" app:layout_constraintTop_toBottomOf="@+id/textView_userName" /> </androidx.constraintlayout.widget.ConstraintLayout> </androidx.cardview.widget.CardView> <TextView android:id="@+id/textView_userName" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginEnd="8dp" android:textSize="20sp" app:layout_constraintBottom_toTopOf="@+id/textView_userMail" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toEndOf="@+id/imageView_avatar" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_chainStyle="packed" />
  16. <?xml version="1.0" encoding="utf-8"?> <androidx.cardview.widget.CardView 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="wrap_content" android:layout_marginTop="8dp"

    android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:layout_marginBottom="4dp" app:cardCornerRadius="8dp" app:cardElevation="4dp"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/imageView_avatar" android:layout_width="60dp" android:layout_height="0dp" android:layout_marginStart="8dp" android:layout_marginTop="10dp" android:layout_marginBottom="10dp" android:background="#673AB7" android:contentDescription="@string/avatar" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintDimensionRatio="1" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:srcCompat="@tools:sample/avatars" /> <TextView android:id="@+id/textView_userName" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginEnd="8dp" android:textSize="20sp" app:layout_constraintBottom_toTopOf="@+id/textView_userMail" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toEndOf="@+id/imageView_avatar" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_chainStyle="packed" /> <TextView android:id="@+id/textView_userMail" android:layout_width="0dp" android:layout_height="wrap_content" android:textSize="16sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="@+id/textView_userName" app:layout_constraintStart_toStartOf="@+id/textView_userName" app:layout_constraintTop_toBottomOf="@+id/textView_userName" /> </androidx.constraintlayout.widget.ConstraintLayout> </androidx.cardview.widget.CardView> <TextView android:id="@+id/textView_userMail" android:layout_width="0dp" android:layout_height="wrap_content" android:textSize="16sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="@+id/textView_userName" app:layout_constraintStart_toStartOf="@+id/textView_userName" app:layout_constraintTop_toBottomOf="@+id/textView_userName" />
  17. data class Users ( val userList: List<User> ) data class

    User ( val id: Long, val email: String, val firstName: String, val lastName: String, val avatar: String )
  18. data class Users ( val userList: List<User> ) { companion

    object { fun parserFromJson(json: JSONObject) : Users { val jsonArray: JSONArray = json.getJSONArray("data") var userList: MutableList<User> = mutableListOf() for (jsonObj: JSONObject in jsonArray) { val id: Long = jsonObj.getLong("id") val email: String = jsonObj.getString("email") val firstName: String = jsonObj.getString("first_name") val lastName: String = jsonObj.getString("last_name") val avatar: String = jsonObj.getString("avatar") userList.add(User(id, email, firstName, lastName, avatar)) } return Users(userList) } } }
  19. class UserListAdapter(private val userList: List<User>, val onClick: ((position: Int) ->

    Unit)) : RecyclerView.Adapter<UserViewHolder>() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder { val itemView = LayoutInflater.from(parent.context) .inflate(R.layout.item_user, parent, false) return UserViewHolder(itemView, onClick) } override fun getItemCount(): Int { return userList.size } override fun onBindViewHolder(holder: UserViewHolder, position: Int) { holder.setupUI(userList[position]) } }
  20. class UserViewHolder(itemView: View, onClick: ((position: Int) -> Unit)) : RecyclerView.ViewHolder(itemView)

    { init { itemView.setOnClickListener { onClick(adapterPosition) } } fun setupUI(user: User) { Glide.with(itemView).load(user.avatar).into(itemView.imageView_avatar) itemView.textView_userName.text = "${user.firstName} ${user.lastName}" itemView.textView_userMail.text = user.email } }
  21. class APIManager { val domain = "https://reqres.in/api"; fun getUsers(success: (Users)

    -> Unit) { val urlString = "$domain/users?per_page=100" val connection = URL(urlString).openConnection() as HttpsURLConnection try { val jsonString = connection.inputStream.bufferedReader().readText() val users = Users.parserFromJson(JSONObject(jsonString)) success(users) } catch (e: Exception) { Log.d(e.toString(), "") } finally { connection.disconnect() } } }
  22. thread { APIManager().getUsers { users -> runOnUiThread { recycleView_userList.layoutManager =

    LinearLayoutManager(this) recycleView_userList.adapter = UserListAdapter(users.userList, onClick = { position -> val intent = Intent(this, RestartActivity::class.java) intent.putExtra(R.string.user_no.toString(), position) this.startActivity(intent) }) } } }
  23. import 'package:flutter/material.dart'; class HomePage extends StatefulWidget { @override _HomePageState createState()

    => _HomePageState(); } class _HomePageState extends State<HomePage> { @override Widget build(BuildContext context) { return Container(); } }
  24. class _HomePageState extends State<HomePage> { List<User> currentUserList; @override Widget build(BuildContext

    context) { var hud = Container( alignment: Alignment.center, child: CircularProgressIndicator(), ); return Scaffold( appBar: AppBar( title: Text("ListView & API"), ), body: Container( child: SafeArea( child: (currentUserList == null) ? hud : listView }
  25. ListView.builder( itemExtent: 80, itemCount: (currentUserList == null) ? 0 :

    currentUserList.length, itemBuilder: (ctx, idx) { return …; } )
  26. Card( child: ListTile( leading: Container( constraints: BoxConstraints(minWidth: 60, minHeight: 60),

    color: Colors.black38, child: Image.network(user.avatar, fit: BoxFit.fill), ), title: Text("${user.firstName} ${user.lastName}"), subtitle: Text(user.email), ) )
  27. Users reqResFromJson(String str) => Users.fromJson(json.decode(str)); String reqResToJson(Users data) => json.encode(data.toJson());

    class Users { Users({ this.page, this.perPage, this.total, this.totalPages, this.userList, }); int page; int perPage; int total; int totalPages; List<User> userList; factory Users.fromJson(Map<String, dynamic> json) => Users( page: json["page"], perPage: json["per_page"], total: json["total"], totalPages: json["total_pages"], userList: List<User>.from(json["data"].map((x) => User.fromJson(x))), ); Map<String, dynamic> toJson() => { "page": page, "per_page": perPage, "total": total, "total_pages": totalPages, "data": List<dynamic>.from(userList.map((x) => x.toJson())), }; }
  28. import 'dart:io'; class APIManager { void getUsers(UsersCallback success) async {

    try { final httpClient = HttpClient(); var request = await httpClient.getUrl(Uri.parse(urlString)); var response = await request.close(); if (response.statusCode == HttpStatus.ok) { var jsonString = await response.transform(utf8.decoder).join(); var jsonMap = jsonDecode(jsonString); var users = Users.fromJson(jsonMap); success(users); httpClient.close(); } else { print("Http NG"); } } catch (exp) { print("Http Fail is $exp"); }
  29. class WithoutThemePage extends StatelessWidget { @override Widget build(BuildContext context) {

    return Container( alignment: Alignment.center, child: Text("WithoutTheme"), ); } }
  30. class RunOutOfRoomPage extends StatelessWidget { @override Widget build(BuildContext context) {

    return Scaffold( body: SafeArea( child: Column( children: [ Container( color: Color(0xFF7ACDF4), width: 1000, height: 100, ), Container( color: Color(0xFF145C9B), width: 1000, height: 1000, }
  31. void main() { runApp(MyApp()); } class MyApp extends StatelessWidget {

    @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: Scaffold( body: Container( alignment: Alignment.center, child: OutlineButton( onPressed: (){ Navigator.push(context, MaterialPageRoute( builder: (context) => SecondPage() }
  32. func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) {