Open NguyenAnhTuan1912 opened 1 year ago
Giải thích cách tính "bước di chuyển" cho Dot index. Trước khi vào phần này thì nói sơ qua một số thứ đi.
Chắc cái này ai cũng biết rồi nhưng vẫn nói lại, trong một view, thì sẽ có gốc toạ độ là từ góc trên cùng bên trái gọi là O (0; 0)
. Nên khi một view (box) nào đó di chuyển theo chiều dương, thì sẽ có xu hướng đi sang bên phải đối với trục Y và đi xuống dưới đối với trục X.
Và nó sẽ không di chuyển từ tâm của box mà sẽ đi từ đi trên cùng bên trái của box.
Ok, quay lại với bài của mình. Dot index có vai trò chỉ cho người dùng là Tab button nào đã được bấm (cho biết họ đang ở screen nào), thì dot index đó phải di chuyển qua lại giữa các button và phải nằm ở giữa button đó.
Trước hết thì xem ngữ cảnh của mình là như nào đã. Đầu tiên, tụi mình có một bottom bar với một chiều dài bất kì gọi là BottomBarWidth
. BottomBar này có padding bên trong được gọi là BottomBarVPadding
.
Tiếp theo, tụi mình sẽ có n
icon, với mỗi icon được bọc trong một là Icon container, mỗi container này có độ rộng là IconContainerWidth
. Các Icon container này được bọc trong button (width, height của button này bằng với _Icon container, cho nên tính width, height của icon container luôn), và container bọc bên ngoài các button này là Tab buttons container có độ rộng là TabButtonsContainerWidth
.
Cuối cùng, cứ cách mỗi một Tab button thì có một khoảng trống ở giữa, nên với n
số Tab button thì sẽ có n - 1
Khoảng trống, mỗi khoảng trống như thế có độ rộng là TabButtonSpaceWidth
.
Ok phần mở đầu đã xong, bây giờ tới phần chính, tính bước di chuyển cho Dot index. Như lý thuyết đã nói ở trên thì khi di chuyển, box sẽ lấy góc trên cùng bên trái làm gốc và tương tự với hình tròn, nó cũng chọn điểm như vậy làm gốc.
Và bây giờ tụi mình cần Dot index di chuyển từ ở giữa Tab button này sang chính giữa của Tab button khác. Trước tiên, để Dot index nằm ngay giữa Tab button thì chúng ta cần phải lấy IconContainerWidth / 2 - DotWidth / 2
. Nên chúng ta có
CenterDotDistance = IconContainerWidth / 2 - DotWidth / 2
Tiếp theo, để Dot index có thể đến được center của Tab button tiếp theo, thì chúng ta sẽ lấy TabButtonSpaceWidth + CenterDotDistance + (IconContainerWidth - CenterDotDistance)
. Lúc này, gốc của Dot index không nằm ở chính giữa Tab button, mà nó nằm cách center của Tab button một khoảng là DotWidth / 2
về bên trái, cho nên góc của Dot index cần phải chạm đến width của Tab button (hay là của Icon container), cho nên mình phải lấy chiều rộng của Tab button trừ đi khoảng cách để center Dot index là ra phần khoảng cách còn lại cần phải di chuyển.
Ok, khi đó phần còn lại là việc Dot index sẽ di chuyển một khoảng cách là TabButtonSpaceWidth
để đi qua tới Tab button t iếp theo và tiếp tục di chuyển với khoảng cách là CenterDotDistance
nữa là Dot index đã được center. Như vậy thì chúng ta sẽ có công thức như sau:
DotMoveDistance = (IconContainerWidth - CenterDotDistance) + TabButtonSpaceWidth + CenterDotDistance
.
Mọi thứ bây giờ đã khá là dễ dàng hơn, khi mà Dot index muốn chuyển tới vị trí của Tab button nào thì chỉ cần nhân DotMoveDistance
với index của Tab button đó. Ví dụ như Dot index đang ở Home (index = 0) và Dot index cần di chuyển tới Blogs (index = 3) thì chỉ việc lấy DotMoveDistance * 3
là được.
Tuy nhiên nhiêu đó vẫn chưa đủ, còn khoảng CenterDotDistance
ban đầu của Tab button đầu tiên nữa (Bời vì Dot index bắt đầu từ 0 và kết thúc ở TabButtonsContainerWidth
), cho nên trong quá trính tính toán vị trí cho Dot index, thì phải cộng thêm CenterDotDistance
vào. Nên ta có
ToValue = DotMoveDistance * index + CenterDotDistance
;
Change
Original version by Phuong, change by Tuan
Lời mở đầu
Trước khi đến phần giải thích thì nói sơ qua một số thứ
master
.Component này dùng để làm gì?
Theo như React Navigation, tụi mình có 3 option để navigate screen:
Sub Screen
sẽ được pop vào Stack và hiển thị đè lênRoot Screen
hoặc cácSub Screen
khác).Trong bài này thì chỉ nói chủ yếu về
Tab
. Sự khác biệt của cả ba là ở behaviour và appearance.Giống với routing ở Browser, thì mỗi screen khi được nhấn thì nó sẽ được render ra màn hình mà sẽ không có sự xuất hiện của screen khác dưới bất kì hình thức nào. Khi screen mới được navigate, thì các screen khác sẽ được unmount ra khỏi hệ thống view.
Tab
được tạo thông qua một function được cung cấp mới React Navigation. Đúng như tên gọi thì nó sẽ tập chung vào phầnBottom
và hành vi củaTab
.Vì cái tên thì có thể gây hiểu nhầm, function này trả về một component cho phép dev quản lý việc navigate các screen thông qua Navigation Bar nằm ở dưới. Như thế thì có thể hiểu, component này cho phép mình có thể custom BottomBar để làm Navigation Bar (Quan trọng).
Một số sửa đổi
Tab.Screen
sẽ không còn 2 props làtabBarIcon
vàlisteners
nữa, thay vào vào đó là BottomBar (Component).Từ Inline thành External
Làm gọn lại Component, file JSX chứa component đó. Code cũ
Code mới
Thay đổi
Tab.Screen
Bời vì cần phài có một custom BottomBar mới cho nên phải thay đổi. Code cũ:
Code mới:
Thêm custom BottomBar
Mục đích: tạo ra một bottom bar, có thể tương tác và chuyển screen được. Vì component này khá là nhiều, cho nên t sẽ phân tách nó ra như sau:
state
,descriptors
,navigation
,tabOffsetValue
và vai trò của từng tham số này là.rotue: { name: 'Home', component: Home }
được định nghĩa từTab.Screen
.options
của một route đã được định nghĩa ởTab.Screen
.state.routes
. Tạo ra cácTouchableOpacity
.Ok, đó là ý tưởng, giờ thì đi đến từng phần: GroupBottomTab gồm một Container bọc bên ngoài một dot index container và Tab buttons container. Trong đó, dùng state.route.map để lấy thông tin các route như đã nói ở trên, tổng hợp lại để tạo ra Tab button.
Bên trong
{state.route.map((route, index) => {})}
Object
options
sẽ được lấy từ trong descriptors theo route.key (các key này đã được tạo từ trrước, nó giống như id để mình lấy thông tin thôi). Check xem button này có focus hay không khá đơn giản, chỉ cần checkindex
của nó vớistate.index
. Nếu nhưstate.index
đang là 1, thì có nghĩa là người đùng đang ấn vào nút thứ 2 (bắt đầu từ 0), cho khi render lại nó sẽ biết được là button thứ 2 đang focus.Tổng hợp thông tin và tạo ra function xử lý sự kiện navigate.
Trước tiên nó sẽ tổng hợp thông tin của event thông qua biến
event
được khai bảo ở bước đầu tiên. Với những nút chưa focus thì mới có thể navigate với route mà nó đại diện thôi đúng không, cho nên ở đây chúng ta sẽ check thêm là nếu như nút này đang focus và defaultPrevented hay chưa? Nếu chả 2 đều chưa thì chúng ta mới có thể navigate. Lúc này khi xử lý navigate, default behaviour mới được prevent. Cuối cùng là sau khi chuyển qua screen mới thì dot index sẽ di chuyển nhờ hàm Animate.spring(). Hàm này nhận về vị trí cũ của dot và vị trí mới của dot, sau đó bắt đầu quá trình transform.Phần còn lại là tổng hợp các thông tin và tạo component thôi, nên cũng không có gì khó
Tại đây,
tabOffsetValue
sẽ dùng để set value mới chotranslateX()
, vì thế dot index mới di chuyển.Ok chỉ có vậy thôi, có gì bàn thêm ở dưới.