الاثنين راح يعملوا نفس الامر اضافة عنوان للـ NanvigationStack او NavigationView
لكن في فرق جوهري بينهم
اولا navigationTitle فقط يستقبل String
بمعنى ماتقدر تضيف صور او غيره
ايضا مافي طريقة مباشره لتغير لون النص، او حجمه الخ
مثال للكود بإستخدام navigationTitle
struct ContentView: View {
var body: some View {
NavigationStack {
List {
NavigationLink("Go to detail A", value: "Show A")
}
.navigationDestination(for: String.self) { textValue in
if textValue == "Show A" {
DetailView(text: textValue)
} else {
FinalView(text: textValue)
}
}
.navigationTitle("A View")
.navigationBarTitleDisplayMode(.inline)
}
}
}
struct DetailView: View {
let text: String
var body: some View {
List {
NavigationLink("Go to detail B", value: "Show B")
}
.navigationTitle("B View")
}
}
struct FinalView: View {
let text: String
var body: some View {
VStack {
Text("Detail view showing")
Text(text)
}
.navigationTitle("C View")
}
}

مثال اخر لنفس الكود بإستخدام
ToolbarItem(placement: .principal)
struct ContentView: View {
var body: some View {
NavigationStack {
List {
NavigationLink("Go to detail A", value: "Show A")
}
.navigationDestination(for: String.self) { textValue in
if textValue == "Show A" {
DetailView(text: textValue)
} else {
FinalView(text: textValue)
}
}
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .principal) {
Text ("A View")
.bold()
}
}
}
}
}
struct DetailView: View {
let text: String
var body: some View {
List {
NavigationLink("Go to detail B", value: "Show B")
}
.toolbar {
ToolbarItem(placement: .principal) {
Text ("B View")
.bold()
}
}
}
}
struct FinalView: View {
let text: String
var body: some View {
VStack {
Text("Detail view showing")
Text(text)
}
.toolbar {
ToolbarItem(placement: .principal) {
Text ("C View")
.bold()
}
}
}
}

هل اختلف شي ؟ ظاهريا لا
لكن بسبب استخدام
ToolbarItem(placement: .principal)
صار عباره عن View بمعنى اقدر اغير لون الخط ، حجمه الخ ايضا اقدر اغيره لصورة مثل كذا
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .principal) {
Image(systemName: "house.fill")
.bold()
}
}

ايضا اقدر اخليه عند الضغط على العنوان يظهر Menu
مثل كذا
.toolbar {
ToolbarItem(placement: .principal) {
Menu( "Menu" ) {
Button( "Duplicate", action: {})
Button("Rename", action: {})
Button("Delete...", action: {})
}
}
}

مثل كذا بإختصار اقدر اسوي اي شي ابغاه
لكن هناك عيب لـ
ToolbarItem(placement: .principal)
وميزة لـ navigationTitle
الميزة لـ navigationTitle عند التعليق على زر الرجوع
تستطيع التنقل بين الصفحات وعنوان الصفحات يظل ظاهر
لكن عند استخدام ToolbarItem
العنواين تختفي ولكن تستطيع التنقل بين الصفحات بدون مشاكل
كيف تستفيد من الميزتين ؟ حرية التخصيص بإستخدام ToolbarItem
مع ظهور العنوان عند الضغط على زر التراجع !
بإختصار استخدام الاثنين مع بعض !
لانه ToolBar راح يغطي على NavigationTitle او تقدر تقول راح يعمل overriding عليه
struct ContentView: View {
var body: some View {
NavigationStack {
List {
NavigationLink("Go to detail A", value: "Show A")
}
.navigationDestination(for: String.self) { textValue in
if textValue == "Show A" {
DetailView(text: textValue)
} else {
FinalView(text: textValue)
}
}
.navigationBarTitleDisplayMode(.inline)
.navigationTitle("A View")
.toolbar {
ToolbarItem(placement: .principal) {
Image(systemName: "house.fill")
.bold()
}
}
}
}
}
struct DetailView: View {
let text: String
var body: some View {
List {
NavigationLink("Go to detail B", value: "Show B")
}
.navigationTitle("B View")
.toolbar {
ToolbarItem(placement: .principal) {
Text ("B View")
.bold()
}
}
}
}
struct FinalView: View {
let text: String
var body: some View {
VStack {
Text("Detail view showing")
Text(text)
}
.navigationTitle("C View")
.toolbar {
ToolbarItem(placement: .principal) {
Text ("C View")
.bold()
}
}
}
}
النتيجة
كيف احسن الموضوع هذا ؟
بحيث اقدر استخدمه في كل مكان
المميزات التي اريدها
١- اقدر اضيف عنوان للـ Navigation بحيث يظهر في زر الرجوع
٢- اقدر اضيف اي نوع من الـ View بمعنى يكون عام وماهو محدد بنوع معين
نقدر نعمل Generic modifier
بهذه الطريقة
struct CustomNavigationTitleModifier<CustomView: View>: ViewModifier {
let title: String
let customView: CustomView
init(title: String, @ViewBuilder customView: () -> CustomView) {
self.title = title
self.customView = customView()
}
func body(content: Content) -> some View {
content
.navigationBarTitleDisplayMode(.inline)
.navigationTitle(title)
.toolbar {
ToolbarItem(placement: .principal) {
customView
}
}
}
}
extension View {
func customNavigationTitle<CustomView: View>(title: String ,@ViewBuilder customView: () -> CustomView) -> some View {
self.modifier(CustomNavigationTitleModifier(title: title, customView: customView))
}
}
ونستخدمها هذه الطريقة
struct ContentView: View {
var body: some View {
NavigationStack {
List {
NavigationLink("Go to detail A", value: "Show A")
}
.navigationDestination(for: String.self) { textValue in
if textValue == "Show A" {
DetailView(text: textValue)
} else {
FinalView(text: textValue)
}
}
.customNavigationTitle(title: "A View") {
Image(systemName: "house.fill")
.bold()
}
}
}
}
struct DetailView: View {
let text: String
var body: some View {
List {
NavigationLink("Go to detail B", value: "Show B")
}
.customNavigationTitle(title: "B View") {
Text("B View")
.bold()
}
}
}
struct FinalView: View {
let text: String
var body: some View {
VStack {
Text("Detail view showing")
Text(text)
}
.customNavigationTitle(title: "C View") {
Text("C View")
.bold()
}
}
}
