1. مقدمه
ویجت ها چیست؟
برای توسعه دهندگان Flutter، تعریف رایج ویجت به اجزای UI اشاره دارد که با استفاده از چارچوب Flutter ایجاد شده اند. در زمینه این کد لبه، ویجت به یک نسخه کوچک از یک برنامه اطلاق می شود که بدون باز کردن برنامه، دیدی به اطلاعات برنامه ارائه می دهد. در اندروید، ویجت ها در صفحه اصلی فعال می شوند. در iOS، آنها را می توان به صفحه اصلی، صفحه قفل یا نمای امروز اضافه کرد.
یک ویجت چقدر می تواند پیچیده باشد؟
بیشتر ویجت های صفحه اصلی ساده هستند. آنها ممکن است حاوی متن اصلی، گرافیک ساده یا، در Android، کنترل های اولیه باشند. Android و iOS هر دو مؤلفهها و ویژگیهای رابط کاربری را که میتوانید استفاده کنید محدود میکنند.
ایجاد رابط کاربری برای ابزارک ها
به دلیل این محدودیتهای رابط کاربری، نمیتوانید مستقیماً رابط کاربری یک ویجت صفحه اصلی را با استفاده از چارچوب Flutter ترسیم کنید. در عوض، میتوانید ویجتهایی را که با چارچوبهای پلتفرمی مانند Jetpack Compose یا SwiftUI ایجاد شدهاند به برنامه Flutter خود اضافه کنید. این نرم افزار کد مثال هایی برای به اشتراک گذاری منابع بین برنامه شما و ابزارک ها برای جلوگیری از بازنویسی UI پیچیده را مورد بحث قرار می دهد.
چیزی که خواهی ساخت
در این کد لبه، ویجتهای صفحه اصلی را در اندروید و iOS برای یک برنامه Flutter ساده با استفاده از بسته home_widget میسازید که به کاربران اجازه میدهد مقالات را بخوانند. ویجت های شما:
- دادههای برنامه Flutter خود را نشان دهید.
- نمایش متن با استفاده از دارایی های فونت به اشتراک گذاشته شده از برنامه Flutter.
- تصویری از ویجت فلاتر رندر شده را نمایش دهید.
این برنامه Flutter شامل دو صفحه (یا مسیر ) است:
- اولی لیستی از مقالات خبری را با عنوان و توضیحات نمایش می دهد.
- دومی مقاله کامل را با نمودار ایجاد شده با استفاده از
CustomPaint
نمایش می دهد.
.
آنچه خواهید آموخت
- نحوه ایجاد ویجت های صفحه اصلی در iOS و اندروید.
- نحوه استفاده از بسته home_widget برای به اشتراک گذاری داده ها بین ویجت صفحه اصلی و برنامه Flutter.
- نحوه کاهش مقدار کدی که برای بازنویسی نیاز دارید.
- چگونه ویجت صفحه اصلی خود را از برنامه Flutter خود به روز کنید.
2. محیط توسعه خود را تنظیم کنید
برای هر دو پلتفرم، به Flutter SDK و یک IDE نیاز دارید. برای کار با Flutter می توانید از IDE دلخواه خود استفاده کنید. این می تواند Visual Studio Code با پسوند Dart Code و Flutter یا Android Studio یا IntelliJ با نصب پلاگین Flutter و Dart باشد.
برای ایجاد ویجت صفحه اصلی iOS:
- می توانید این کد لبه را بر روی یک دستگاه فیزیکی iOS یا شبیه ساز iOS اجرا کنید.
- شما باید یک سیستم macOS را با Xcode IDE پیکربندی کنید. این کامپایلر مورد نیاز برای ساخت نسخه iOS برنامه شما را نصب می کند.
برای ایجاد ویجت صفحه اصلی Android:
- می توانید این کد لبه را بر روی یک دستگاه اندروید فیزیکی یا شبیه ساز اندروید اجرا کنید.
- شما باید سیستم توسعه خود را با Android Studio پیکربندی کنید. این کامپایلر مورد نیاز برای ساخت نسخه اندروید برنامه شما را نصب می کند.
کد شروع را دریافت کنید
نسخه اولیه پروژه خود را از GitHub دانلود کنید
از خط فرمان، مخزن GitHub را در دایرکتوری flutter-codelabs کلون کنید:
$ git clone https://github.com/flutter/codelabs.git flutter-codelabs
پس از شبیهسازی مخزن، میتوانید کد این codelab را در فهرست flutter-codelabs/homescreen_codelab پیدا کنید. این دایرکتوری شامل کد پروژه تکمیل شده برای هر مرحله در Codelab می باشد.
برنامه شروع را باز کنید
دایرکتوری flutter-codelabs/homescreen_codelab/step_03
در IDE دلخواه خود باز کنید.
بسته ها را نصب کنید
تمام بسته های مورد نیاز به فایل pubspec.yaml پروژه اضافه شد. برای بازیابی وابستگی های پروژه، دستور زیر را اجرا کنید:
$ flutter pub get
3. یک ویجت اصلی صفحه اصلی اضافه کنید
ابتدا، ویجت صفحه اصلی را با استفاده از ابزار پلتفرم بومی اضافه کنید.
ایجاد یک ویجت اصلی صفحه اصلی iOS
افزودن پسوند برنامه به برنامه Flutter iOS شبیه افزودن یک برنامه افزودنی به برنامه SwiftUI یا UIKit است:
-
open ios/Runner.xcworkspace
در پنجره ترمینال از فهرست پروژه Flutter خود اجرا کنید. همچنین، روی پوشه ios از VSCode کلیک راست کرده و Open in Xcode را انتخاب کنید. با این کار فضای کاری پیشفرض Xcode در پروژه Flutter شما باز میشود. - File → New → Target را از منو انتخاب کنید. این یک هدف جدید به پروژه اضافه می کند.
- لیستی از الگوها ظاهر می شود. پسوند ویجت را انتخاب کنید.
- "NewsWidgets" را در کادر نام محصول برای این ویجت تایپ کنید. هر دو چک باکس Include Live Activity و Include Configuration Intent را پاک کنید.
کد نمونه را بررسی کنید
هنگامی که یک هدف جدید اضافه می کنید، Xcode کد نمونه را بر اساس الگوی انتخابی شما تولید می کند. برای اطلاعات بیشتر در مورد کد تولید شده و ویجت کیت، به مستندات برنامه افزودنی اپل مراجعه کنید.
ویجت نمونه خود را اشکال زدایی و آزمایش کنید
- ابتدا پیکربندی برنامه Flutter خود را به روز کنید. زمانی که بسته های جدیدی را در برنامه Flutter خود اضافه می کنید و قصد دارید هدفی را در پروژه از Xcode اجرا کنید، باید این کار را انجام دهید. برای به روز رسانی پیکربندی برنامه خود، دستور زیر را در فهرست برنامه Flutter خود اجرا کنید:
$ flutter build ios --config-only
- روی Runner کلیک کنید تا لیستی از اهداف ظاهر شود. هدف ویجتی که به تازگی ایجاد کردید، NewsWidgets را انتخاب کنید و روی Run کلیک کنید. هنگامی که کد ویجت iOS را تغییر می دهید، هدف ویجت را از Xcode اجرا کنید.
- شبیه ساز یا صفحه دستگاه باید یک ویجت اصلی صفحه اصلی را نمایش دهد. اگر آن را نمی بینید، می توانید آن را به صفحه اضافه کنید. روی صفحه اصلی کلیک کنید و نگه دارید سپس روی + در گوشه سمت چپ بالا کلیک کنید.
- نام برنامه را جستجو کنید. برای این کد لبه، "ویجت های صفحه اصلی" را جستجو کنید
- هنگامی که ویجت صفحه اصلی را اضافه کردید، باید متن ساده ای را نشان دهد که زمان می دهد.
ایجاد یک ویجت پایه اندروید
- برای افزودن ویجت صفحه اصلی در اندروید، فایل ساخت پروژه را در Android Studio باز کنید. می توانید این فایل را در android/build.gradle پیدا کنید. یا روی پوشه اندروید از VSCode کلیک راست کرده و Open in Android Studio را انتخاب کنید.
- پس از ساخت پروژه، فهرست برنامه را در گوشه سمت چپ بالا پیدا کنید. ویجت صفحه اصلی جدید خود را به این فهرست اضافه کنید. روی فهرست کلیک راست کنید، New -> Widget -> App Widget را انتخاب کنید.
- اندروید استودیو فرم جدیدی را نمایش می دهد. اطلاعات اولیه درباره ویجت صفحه اصلی خود از جمله نام کلاس، مکان، اندازه و زبان مبدأ اضافه کنید
برای این کد لبه، مقادیر زیر را تنظیم کنید:
- کادر نام کلاس به NewsWidget
- حداقل عرض (سلول ها) به 3 باز می شود
- حداقل ارتفاع (سلول ها) به 3 باز می شود
کد نمونه را بررسی کنید
هنگامی که فرم را ارسال می کنید، Android Studio چندین فایل ایجاد و به روز می کند. تغییرات مربوط به این کد لبه در جدول زیر فهرست شده است
اقدام | فایل هدف | تغییر دهید |
به روز رسانی | | یک گیرنده جدید اضافه می کند که NewsWidget را ثبت می کند. |
ایجاد کنید | | رابط کاربری ویجت صفحه اصلی را تعریف می کند. |
ایجاد کنید | | پیکربندی ویجت صفحه اصلی شما را تعریف می کند. شما می توانید ابعاد یا نام ویجت خود را در این فایل تنظیم کنید. |
ایجاد کنید | | حاوی کد Kotlin شما برای افزودن قابلیت به ویجت صفحه اصلی شما است. |
شما می توانید جزئیات بیشتری را در مورد این فایل ها در سراسر این کد لبه پیدا کنید.
ویجت نمونه خود را اشکال زدایی و آزمایش کنید
اکنون برنامه خود را اجرا کنید و ویجت صفحه اصلی را ببینید. هنگامی که برنامه را ساختید، به صفحه انتخاب برنامه دستگاه اندرویدی خود بروید و نماد این پروژه Flutter را برای مدت طولانی فشار دهید. ابزارک ها را از منوی بازشو انتخاب کنید.
دستگاه یا شبیه ساز Android ویجت صفحه اصلی پیش فرض شما را برای اندروید نمایش می دهد.
4. داده ها را از برنامه Flutter خود به ویجت صفحه اصلی خود ارسال کنید
می توانید ویجت اصلی صفحه اصلی را که ایجاد کرده اید سفارشی کنید. ویجت صفحه اصلی را برای نمایش عنوان و خلاصه یک مقاله خبری به روز کنید. اسکرین شات زیر نمونه ای از ویجت صفحه اصلی را نشان می دهد که عنوان و خلاصه ای را نشان می دهد.
برای انتقال داده بین برنامه و ویجت صفحه اصلی، باید Dart و کد بومی بنویسید. این بخش این فرآیند را به سه بخش تقسیم می کند:
- نوشتن کد دارت در برنامه Flutter خود که هم اندروید و هم iOS می توانند از آن استفاده کنند
- افزودن قابلیت بومی iOS
- افزودن قابلیت بومی اندروید
استفاده از گروه های برنامه iOS
برای اشتراکگذاری دادهها بین یک برنامه والد iOS و یک برنامه افزودنی ویجت، هر دو هدف باید به یک گروه برنامه تعلق داشته باشند. برای کسب اطلاعات بیشتر درباره گروههای برنامه، به مستندات گروه برنامه اپل مراجعه کنید.
شناسه بسته خود را به روز کنید:
در Xcode به تنظیمات هدف خود بروید. در برگه Signing & Capabilities ، بررسی کنید که شناسه تیم و بسته شما تنظیم شده باشد.
گروه App را هم به هدف Runner و هم به هدف NewsWidgetExtension در Xcode اضافه کنید:
+ Capability -> App Groups را انتخاب کنید و یک App Group جدید اضافه کنید. هم برای هدف Runner (برنامه والد) و هم برای هدف ویجت تکرار کنید.
کد دارت را اضافه کنید
هم برنامههای iOS و Android میتوانند دادهها را با یک برنامه Flutter به روشهای مختلف به اشتراک بگذارند. برای برقراری ارتباط با این برنامهها، از فروشگاه key/value
محلی دستگاه استفاده کنید. iOS این فروشگاه را UserDefaults
و اندروید این فروشگاه را SharedPreferences
می نامد. بسته home_widget این APIها را میپیچد تا ذخیره دادهها را در هر یک از پلتفرمها ساده کند و ویجتهای صفحه اصلی را قادر میسازد تا دادههای بهروز شده را جمعآوری کند.
داده های عنوان و توضیحات از فایل news_data.dart
آمده است. این فایل حاوی داده های ساختگی و یک کلاس داده NewsArticle
است.
lib/news_data.dart
class NewsArticle {
final String title;
final String description;
final String? articleText;
NewsArticle({
required this.title,
required this.description,
this.articleText = loremIpsum,
});
}
مقادیر عنوان و توضیحات را به روز کنید
برای افزودن قابلیت بهروزرسانی ویجت صفحه اصلی از برنامه Flutter، به فایل lib/home_screen.dart
بروید. محتویات فایل را با کد زیر جایگزین کنید. سپس، <YOUR APP GROUP>
را با شناسه گروه برنامه خود جایگزین کنید.
lib/home_screen.dart
import 'package:flutter/material.dart';
import 'package:home_widget/home_widget.dart'; // Add this import
import 'article_screen.dart';
import 'news_data.dart';
// TODO: Replace with your App Group ID
const String appGroupId = '<YOUR APP GROUP>'; // Add from here
const String iOSWidgetName = 'NewsWidgets';
const String androidWidgetName = 'NewsWidget'; // To here.
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
void updateHeadline(NewsArticle newHeadline) { // Add from here
// Save the headline data to the widget
HomeWidget.saveWidgetData<String>('headline_title', newHeadline.title);
HomeWidget.saveWidgetData<String>(
'headline_description', newHeadline.description);
HomeWidget.updateWidget(
iOSName: iOSWidgetName,
androidName: androidWidgetName,
);
} // To here.
class _MyHomePageState extends State<MyHomePage> {
@override // Add from here
void initState() {
super.initState();
HomeWidget.setAppGroupId(appGroupId);
// Mock read in some data and update the headline
final newHeadline = getNewsStories()[0];
updateHeadline(newHeadline);
} // To here.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Top Stories'),
centerTitle: false,
titleTextStyle: const TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
color: Colors.black)),
body: ListView.separated(
separatorBuilder: (context, idx) {
return const Divider();
},
itemCount: getNewsStories().length,
itemBuilder: (context, idx) {
final article = getNewsStories()[idx];
return ListTile(
key: Key('$idx ${article.hashCode}'),
title: Text(article.title!),
subtitle: Text(article.description!),
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) {
return ArticleScreen(article: article);
},
),
);
},
);
},
));
}
}
تابع updateHeadline
جفت های کلید/مقدار را در حافظه محلی دستگاه شما ذخیره می کند. کلید headline_title
مقدار newHeadline.title
را نگه می دارد. کلید headline_description
مقدار newHeadline.description
را نگه می دارد. این تابع همچنین به پلتفرم بومی اطلاع میدهد که دادههای جدید برای ویجتهای صفحه اصلی قابل بازیابی و رندر هستند.
floatingActionButton را تغییر دهید
هنگامی که دکمه floatingActionButton
فشار داده می شود، تابع updateHeadline
را فراخوانی کنید:
lib/article_screen.dart
// New: import the updateHeadline function
import 'home_screen.dart';
...
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text('Updating home screen widget...'),
));
// New: call updateHeadline
updateHeadline(widget.article);
},
label: const Text('Update Homescreen'),
),
...
با این تغییر، زمانی که کاربر دکمه Update Headline را از صفحه مقاله فشار می دهد، جزئیات ویجت صفحه اصلی به روز می شود.
کد iOS را برای نمایش داده های مقاله به روز کنید
برای به روز رسانی ویجت صفحه اصلی برای iOS، از Xcode استفاده کنید.
فایل NewsWidgets.swift
را در Xcode باز کنید:
TimelineEntry
را پیکربندی کنید .
ساختار SimpleEntry
را با کد زیر جایگزین کنید:
ios/NewsWidgets/NewsWidgets.swift
// The date and any data you want to pass into your app must conform to TimelineEntry
struct NewsArticleEntry: TimelineEntry {
let date: Date
let title: String
let description:String
}
این ساختار NewsArticleEntry
دادههای ورودی را برای ارسال به ویجت صفحه اصلی هنگام بهروزرسانی تعریف میکند. نوع TimelineEntry
به پارامتر تاریخ نیاز دارد. برای اطلاعات بیشتر در مورد پروتکل TimelineEntry
، اسناد TimelineEntry اپل را بررسی کنید.
View
که محتوا را نمایش می دهد ویرایش کنید
ویجت صفحه اصلی خود را تغییر دهید تا به جای تاریخ، عنوان و توضیحات مقاله خبری نمایش داده شود. برای نمایش متن در SwiftUI، از نمای Text
استفاده کنید. برای قرار دادن نماها روی هم در SwiftUI، از نمای VStack
استفاده کنید.
نمای NewsWidgetEntryView
ایجاد شده را با کد زیر جایگزین کنید:
ios/NewsWidgets/NewsWidgets.swift
//View that holds the contents of the widget
struct NewsWidgetsEntryView : View {
var entry: Provider.Entry
var body: some View {
VStack {
Text(entry.title)
Text(entry.description)
}
}
}
ارائهدهنده را ویرایش کنید تا به ویجت صفحه اصلی بگویید چه زمانی و چگونه بهروزرسانی شود
کد زیر را جایگزین Provider
موجود کنید. سپس، شناسه گروه برنامه خود را با <گروه برنامه شما> جایگزین کنید:
ios/NewsWidgets/NewsWidgets.swift
struct Provider: TimelineProvider {
// Placeholder is used as a placeholder when the widget is first displayed
func placeholder(in context: Context) -> NewsArticleEntry {
// Add some placeholder title and description, and get the current date
NewsArticleEntry(date: Date(), title: "Placeholder Title", description: "Placeholder description")
}
// Snapshot entry represents the current time and state
func getSnapshot(in context: Context, completion: @escaping (NewsArticleEntry) -> ()) {
let entry: NewsArticleEntry
if context.isPreview{
entry = placeholder(in: context)
}
else{
// Get the data from the user defaults to display
let userDefaults = UserDefaults(suiteName: <YOUR APP GROUP>)
let title = userDefaults?.string(forKey: "headline_title") ?? "No Title Set"
let description = userDefaults?.string(forKey: "headline_description") ?? "No Description Set"
entry = NewsArticleEntry(date: Date(), title: title, description: description)
}
completion(entry)
}
// getTimeline is called for the current and optionally future times to update the widget
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
// This just uses the snapshot function you defined earlier
getSnapshot(in: context) { (entry) in
// atEnd policy tells widgetkit to request a new entry after the date has passed
let timeline = Timeline(entries: [entry], policy: .atEnd)
completion(timeline)
}
}
}
Provider
در کد قبلی با TimelineProvider
مطابقت دارد. Provider
سه روش مختلف دارد:
- روش
placeholder
زمانی که کاربر برای اولین بار ویجت صفحه اصلی را پیشنمایش میکند، یک ورودی مکاننما ایجاد میکند.
- متد
getSnapshot
دادهها را از پیشفرضهای کاربر میخواند و ورودی را برای زمان فعلی ایجاد میکند. - متد
getTimeline
ورودی های جدول زمانی را برمی گرداند. این به زمانی کمک می کند که نقاط قابل پیش بینی به موقع برای به روز رسانی محتوای خود داشته باشید. این کد لبه از تابع getSnapshot برای بدست آوردن وضعیت فعلی استفاده می کند. متد.atEnd
به ویجت صفحه اصلی میگوید پس از گذشت زمان فعلی، دادهها را تازهسازی کند.
NewsWidgets_Previews
را نظر دهید
استفاده از پیش نمایش ها خارج از محدوده این نرم افزار کد است. برای جزئیات بیشتر در مورد پیشنمایش ویجتهای صفحه اصلی SwiftUI به مستندات اپل در مورد ابزارکهای اشکالزدایی مراجعه کنید.
همه فایل ها را ذخیره کنید و برنامه و هدف ویجت را دوباره اجرا کنید.
اهداف را دوباره اجرا کنید تا تأیید کنید که برنامه و ویجت صفحه اصلی کار می کنند.
- برای اجرای هدف برنامه، طرح برنامه را در Xcode انتخاب کنید.
- برای اجرای هدف برنامه افزودنی، طرح برنامه افزودنی را در Xcode انتخاب کنید.
- به صفحه مقاله در برنامه بروید.
- برای به روز رسانی تیتر روی دکمه کلیک کنید. ویجت صفحه اصلی نیز باید عنوان را به روز کند.
کد اندروید را به روز کنید
ویجت XML صفحه اصلی را اضافه کنید.
در Android Studio، فایل های تولید شده در مرحله قبل را به روز کنید. فایل res/layout/news_widget.xml
. ساختار و طرح بندی ویجت صفحه اصلی شما را مشخص می کند. کد را در گوشه سمت راست بالا انتخاب کنید و محتوای آن فایل را با کد زیر جایگزین کنید:
android/app/res/layout/news_widget.xml
<RelativeLayout 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:id="@+id/widget_container"
style="@style/Widget.Android.AppWidget.Container"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@android:color/white"
android:theme="@style/Theme.Android.AppWidgetContainer">
<TextView
android:id="@+id/headline_title"
style="@style/Widget.Android.AppWidget.InnerView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:background="@android:color/white"
android:text="Title"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:id="@+id/headline_description"
style="@style/Widget.Android.AppWidget.InnerView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/headline_title"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="4dp"
android:background="@android:color/white"
android:text="Title"
android:textSize="16sp" />
</RelativeLayout>
این XML دو نمای متنی را تعریف می کند، یکی برای عنوان مقاله و دیگری برای توضیحات مقاله. این نماهای متنی نیز استایل را تعریف می کنند. در سراسر این کد لبه به این فایل باز خواهید گشت.
قابلیت NewsWidget را به روز کنید
فایل کد منبع NewsWidget.kt
Kotlin را باز کنید. این فایل شامل یک کلاس تولید شده به نام NewsWidget
است که کلاس AppWidgetProvider
را گسترش می دهد.
کلاس NewsWidget
شامل سه متد از سوپرکلاس خود است. روش onUpdate
را تغییر خواهید داد. اندروید این روش را برای ویجت ها در فواصل زمانی ثابت فراخوانی می کند.
محتوای فایل NewsWidget.kt
را با کد زیر جایگزین کنید:
android/app/java/com.mydomain.homescreen_widgets/NewsWidget.kt
// Import will depend on App ID.
package com.mydomain.homescreen_widgets
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import android.widget.RemoteViews
// New import.
import es.antonborri.home_widget.HomeWidgetPlugin
/**
* Implementation of App Widget functionality.
*/
class NewsWidget : AppWidgetProvider() {
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray,
) {
for (appWidgetId in appWidgetIds) {
// Get reference to SharedPreferences
val widgetData = HomeWidgetPlugin.getData(context)
val views = RemoteViews(context.packageName, R.layout.news_widget).apply {
val title = widgetData.getString("headline_title", null)
setTextViewText(R.id.headline_title, title ?: "No title set")
val description = widgetData.getString("headline_description", null)
setTextViewText(R.id.headline_description, description ?: "No description set")
}
appWidgetManager.updateAppWidget(appWidgetId, views)
}
}
}
اکنون، هنگامی که onUpdate
فراخوانی می شود، Android با استفاده از روش the widgetData.getString()
جدیدترین مقادیر را از حافظه محلی دریافت می کند و سپس setTextViewText
برای تغییر متن نمایش داده شده در ویجت صفحه اصلی فراخوانی می کند.
به روز رسانی ها را تست کنید
برای اطمینان از بهروزرسانی ویجتهای صفحه اصلی با دادههای جدید، برنامه را آزمایش کنید. برای به روز رسانی داده ها، از دکمه Update Home Screen FloatingActionButton
در صفحات مقاله استفاده کنید. ویجت صفحه اصلی شما باید با عنوان مقاله به روز شود.
5. استفاده از فونت های سفارشی برنامه Flutter در ویجت صفحه اصلی iOS خود
تاکنون، ویجت صفحه اصلی را برای خواندن داده هایی که برنامه Flutter ارائه می دهد پیکربندی کرده اید. برنامه Flutter شامل یک فونت سفارشی است که ممکن است بخواهید در ویجت صفحه اصلی استفاده کنید. میتوانید از فونت سفارشی در ویجت صفحه اصلی iOS خود استفاده کنید. استفاده از فونت های سفارشی در ویجت های صفحه اصلی در اندروید در دسترس نیست.
کد iOS را به روز کنید
Flutter دارایی های خود را در باندل اصلی برنامه های iOS ذخیره می کند. میتوانید از کد ویجت صفحه اصلی خود به داراییهای این بسته دسترسی داشته باشید.
در ساختار NewsWidgetsEntryView در فایل NewsWidgets.swift خود، تغییرات زیر را اعمال کنید.
یک تابع کمکی ایجاد کنید تا مسیر دایرکتوری دارایی Flutter را دریافت کنید:
ios/NewsWidgets/NewsWidgets.swift
struct NewsWidgetsEntryView : View {
...
// New: Add the helper function.
var bundle: URL {
let bundle = Bundle.main
if bundle.bundleURL.pathExtension == "appex" {
// Peel off two directory levels - MY_APP.app/PlugIns/MY_APP_EXTENSION.appex
var url = bundle.bundleURL.deletingLastPathComponent().deletingLastPathComponent()
url.append(component: "Frameworks/App.framework/flutter_assets")
return url
}
return bundle.bundleURL
}
...
}
فونت را با استفاده از URL در فایل فونت سفارشی خود ثبت کنید.
ios/NewsWidgets/NewsWidgets.swift
struct NewsWidgetsEntryView : View {
...
// New: Register the font.
init(entry: Provider.Entry){
self.entry = entry
CTFontManagerRegisterFontsForURL(bundle.appending(path: "/fonts/Chewy-Regular.ttf") as CFURL, CTFontManagerScope.process, nil)
}
...
}
برای استفاده از فونت سفارشی خود، نمای متن تیتر را به روز کنید.
ios/NewsWidgets/NewsWidgets.swift
struct NewsWidgetsEntryView : View {
...
var body: some View {
VStack {
// Update the following line.
Text(entry.title).font(Font.custom("Chewy", size: 13))
Text(entry.description)
}
}
...
}
هنگامی که ویجت صفحه اصلی خود را اجرا می کنید، اکنون از فونت سفارشی برای عنوان همانطور که در تصویر زیر نشان داده شده است استفاده می کند:
6. رندر کردن ویجت های فلاتر به عنوان تصویر
در این بخش، نموداری را از برنامه Flutter خود به عنوان ویجت صفحه اصلی نمایش می دهید.
این ویجت چالش بزرگتری نسبت به متنی که در صفحه اصلی نمایش دادهاید فراهم میکند. نمایش نمودار فلاتر بهعنوان یک تصویر بهجای تلاش برای بازسازی آن با استفاده از مؤلفههای رابط کاربری بومی، بسیار سادهتر است.
ویجت صفحه اصلی خود را کد کنید تا نمودار فلاتر شما به صورت فایل PNG ارائه شود. ویجت صفحه اصلی شما می تواند آن تصویر را نمایش دهد.
کد دارت را بنویسید
در سمت Dart، متد renderFlutterWidget
از بسته home_widget اضافه کنید. این روش یک ویجت، یک نام فایل و یک کلید می گیرد. تصویری از ویجت Flutter را برمی گرداند و آن را در یک ظرف مشترک ذخیره می کند. نام تصویر را در کد خود وارد کنید و اطمینان حاصل کنید که ویجت صفحه اصلی می تواند به ظرف دسترسی داشته باشد. key
مسیر کامل فایل را به عنوان یک رشته در حافظه محلی دستگاه ذخیره می کند. این به ویجت صفحه اصلی اجازه می دهد تا در صورت تغییر نام در کد دارت، فایل را پیدا کند.
برای این کد، کلاس LineChart
در فایل lib/article_screen.dart
نمودار را نشان می دهد. متد ساخت آن یک CustomPainter را برمی گرداند که این نمودار را روی صفحه نمایش می دهد.
برای پیاده سازی این ویژگی، فایل lib/article_screen.dart
را باز کنید. بسته home_widget را وارد کنید. سپس کد موجود در کلاس _ArticleScreenState
را با کد زیر جایگزین کنید:
lib/article_screen.dart
import 'package:flutter/material.dart';
// New: import the home_widget package.
import 'package:home_widget/home_widget.dart';
import 'home_screen.dart';
import 'news_data.dart';
...
class _ArticleScreenState extends State<ArticleScreen> {
// New: add this GlobalKey
final _globalKey = GlobalKey();
String? imagePath;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.article.title!),
),
// New: add this FloatingActionButton
floatingActionButton: FloatingActionButton.extended(
onPressed: () async {
if (_globalKey.currentContext != null) {
var path = await HomeWidget.renderFlutterWidget(
const LineChart(),
fileName: 'screenshot',
key: 'filename',
logicalSize: _globalKey.currentContext!.size,
pixelRatio:
MediaQuery.of(_globalKey.currentContext!).devicePixelRatio,
);
setState(() {
imagePath = path as String?;
});
}
updateHeadline(widget.article);
},
label: const Text('Update Homescreen'),
),
body: ListView(
padding: const EdgeInsets.all(16.0),
children: [
Text(
widget.article.description!,
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 20.0),
Text(widget.article.articleText!),
const SizedBox(height: 20.0),
Center(
// New: Add this key
key: _globalKey,
child: const LineChart(),
),
const SizedBox(height: 20.0),
Text(widget.article.articleText!),
],
),
);
}
}
این مثال سه تغییر در کلاس _ArticleScreenState
ایجاد می کند.
یک GlobalKey ایجاد می کند
GlobalKey
زمینه یک ویجت خاص را دریافت می کند که برای بدست آوردن اندازه آن ویجت لازم است.
lib/article_screen.dart
class _ArticleScreenState extends State<ArticleScreen> {
// New: add this GlobalKey
final _globalKey = GlobalKey();
...
}
imagePath را اضافه می کند
ویژگی imagePath
مکان تصویر را که در آن ویجت Flutter ارائه می شود ذخیره می کند.
lib/article_screen.dart
class _ArticleScreenState extends State<ArticleScreen> {
...
// New: add this imagePath
String? imagePath;
...
}
کلیدی را برای رندر به ویجت اضافه می کند
_globalKey
حاوی ویجت Flutter است که به تصویر ارائه می شود. در این مورد، ویجت Flutter مرکزی است که شامل LineChart
است.
lib/article_screen.dart
class _ArticleScreenState extends State<ArticleScreen> {
...
Center(
// New: Add this key
key: _globalKey,
child: const LineChart(),
),
...
}
- ویجت را به عنوان تصویر ذخیره می کند
متد renderFlutterWidget
زمانی فراخوانی می شود که کاربر روی floatingActionButton
کلیک کند. این روش فایل PNG به دست آمده را به عنوان "نمایش" در فهرست کانتینر مشترک ذخیره می کند. این روش همچنین مسیر کامل تصویر را به عنوان کلید نام فایل در حافظه دستگاه ذخیره می کند.
lib/article_screen.dart
class _ArticleScreenState extends State<ArticleScreen> {
...
floatingActionButton: FloatingActionButton.extended(
onPressed: () async {
if (_globalKey.currentContext != null) {
var path = await HomeWidget.renderFlutterWidget(
LineChart(),
fileName: 'screenshot',
key: 'filename',
logicalSize: _globalKey.currentContext!.size,
pixelRatio:
MediaQuery.of(_globalKey.currentContext!).devicePixelRatio,
);
setState(() {
imagePath = path as String?;
});
}
updateHeadline(widget.article);
},
...
}
کد iOS را به روز کنید
برای iOS، کد را بهروزرسانی کنید تا مسیر فایل را از ذخیرهسازی دریافت کنید و با استفاده از SwiftUI، فایل را بهعنوان تصویر نمایش دهید.
فایل NewsWidgets.swift
را باز کنید تا تغییرات زیر را اعمال کنید:
filename
و displaySize
را به ساختار NewsArticleEntry
اضافه کنید
ویژگی filename
رشته ای را که نشان دهنده مسیر فایل تصویری است، نگه می دارد. ویژگی displaySize
اندازه ویجت صفحه اصلی را در دستگاه کاربر نگه می دارد. اندازه ویجت صفحه اصلی برگرفته از context
است.
ios/NewsWidgets/NewsWidgets.swift
struct NewsArticleEntry: TimelineEntry {
...
// New: add the filename and displaySize.
let filename: String
let displaySize: CGSize
}
تابع placeholder
را به روز کنید
یک filename
نگهدارنده مکان و displaySize
را اضافه کنید.
ios/NewsWidgets/NewsWidgets.swift
func placeholder(in context: Context) -> NewsArticleEntry {
NewsArticleEntry(date: Date(), title: "Placeholder Title", description: "Placeholder description", filename: "No screenshot available", displaySize: context.displaySize)
}
نام فایل را از userDefaults
در getSnapshot دریافت کنید
زمانی که ویجت صفحه اصلی به روز می شود، متغیر filename
را روی مقدار filename
در فضای ذخیره سازی userDefaults
تنظیم می کند.
ios/NewsWidgets/NewsWidgets.swift
func getSnapshot(
...
let title = userDefaults?.string(forKey: "headline_title") ?? "No Title Set"
let description = userDefaults?.string(forKey: "headline_description") ?? "No Description Set"
// New: get fileName from key/value store
let filename = userDefaults?.string(forKey: "filename") ?? "No screenshot available"
...
)
ChartImage ایجاد کنید که تصویر را از یک مسیر نمایش دهد
نمای ChartImage
یک تصویر از محتویات فایل تولید شده در سمت دارت ایجاد می کند. در اینجا، اندازه را روی 50٪ از فریم قرار می دهید.
ios/NewsWidgets/NewsWidgets.swift
struct NewsWidgetsEntryView : View {
...
// New: create the ChartImage view
var ChartImage: some View {
if let uiImage = UIImage(contentsOfFile: entry.filename) {
let image = Image(uiImage: uiImage)
.resizable()
.frame(width: entry.displaySize.height*0.5, height: entry.displaySize.height*0.5, alignment: .center)
return AnyView(image)
}
print("The image file could not be loaded")
return AnyView(EmptyView())
}
...
}
از ChartImage در بدنه NewsWidgetsEntryView استفاده کنید
نمای ChartImage را به بدنه NewsWidgetsEntryView اضافه کنید تا ChartImage در ویجت صفحه اصلی نمایش داده شود.
ios/NewsWidgets/NewsWidgets.swift
VStack {
Text(entry.title).font(Font.custom("Chewy", size: 13))
Text(entry.description).font(.system(size: 12)).padding(10)
// New: add the ChartImage to the NewsWidgetEntryView
ChartImage
}
تغییرات را تست کنید
برای آزمایش تغییرات، هم هدف برنامه Flutter (Runner) و هم هدف برنامه افزودنی خود را از Xcode دوباره اجرا کنید. برای دیدن تصویر، به یکی از صفحات مقاله در برنامه بروید و دکمه را فشار دهید تا ویجت صفحه اصلی به روز شود.
کد اندروید را به روز کنید
کد اندروید مانند کد iOS عمل می کند.
- فایل
android/app/res/layout/news_widget.xml
را باز کنید. این شامل عناصر رابط کاربری ویجت صفحه اصلی شما است. محتوای آن را با کد زیر جایگزین کنید:
android/app/res/layout/news_widget.xml
<RelativeLayout 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:id="@+id/widget_container"
style="@style/Widget.Android.AppWidget.Container"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@android:color/white"
android:theme="@style/Theme.Android.AppWidgetContainer">
<TextView
android:id="@+id/headline_title"
style="@style/Widget.Android.AppWidget.InnerView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:background="@android:color/white"
android:text="Title"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:id="@+id/headline_description"
style="@style/Widget.Android.AppWidget.InnerView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/headline_title"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="4dp"
android:background="@android:color/white"
android:text="Title"
android:textSize="16sp" />
<!--New: add this image view -->
<ImageView
android:id="@+id/widget_image"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_below="@+id/headline_description"
android:layout_alignBottom="@+id/headline_title"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="6dp"
android:layout_marginBottom="-134dp"
android:layout_weight="1"
android:adjustViewBounds="true"
android:background="@android:color/white"
android:scaleType="fitCenter"
android:src="@android:drawable/star_big_on"
android:visibility="visible"
tools:visibility="visible" />
</RelativeLayout>
این کد جدید یک تصویر به ویجت صفحه اصلی اضافه می کند که (در حال حاضر) یک نماد ستاره عمومی را نمایش می دهد. این نماد ستاره را با تصویری که در کد Dart ذخیره کرده اید جایگزین کنید.
- فایل
NewsWidget.kt
را باز کنید. محتوای آن را با کد زیر جایگزین کنید:
android/app/java/com.mydomain.homescreen_widgets/NewsWidget.kt
// Import will depend on App ID.
package com.mydomain.homescreen_widgets
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.widget.RemoteViews
import java.io.File
import es.antonborri.home_widget.HomeWidgetPlugin
/**
* Implementation of App Widget functionality.
*/
class NewsWidget : AppWidgetProvider() {
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray,
) {
for (appWidgetId in appWidgetIds) {
val widgetData = HomeWidgetPlugin.getData(context)
val views = RemoteViews(context.packageName, R.layout.news_widget).apply {
val title = widgetData.getString("headline_title", null)
setTextViewText(R.id.headline_title, title ?: "No title set")
val description = widgetData.getString("headline_description", null)
setTextViewText(R.id.headline_description, description ?: "No description set")
// New: Add the section below
// Get chart image and put it in the widget, if it exists
val imageName = widgetData.getString("filename", null)
val imageFile = File(imageName)
val imageExists = imageFile.exists()
if (imageExists) {
val myBitmap: Bitmap = BitmapFactory.decodeFile(imageFile.absolutePath)
setImageViewBitmap(R.id.widget_image, myBitmap)
} else {
println("image not found!, looked @: ${imageName}")
}
// End new code
}
appWidgetManager.updateAppWidget(appWidgetId, views)
}
}
}
این کد دارت یک اسکرین شات را با کلید filename
در حافظه محلی ذخیره می کند. همچنین مسیر کامل تصویر را دریافت می کند و یک شی File
از آن ایجاد می کند. اگر تصویر وجود داشته باشد، کد Dart تصویر جدید را در ویجت صفحه اصلی جایگزین می کند.
- برنامه خود را دوباره بارگیری کنید و به صفحه مقاله بروید. Update Homescreen را فشار دهید. ویجت صفحه اصلی نمودار را نمایش می دهد.
7. مراحل بعدی
تبریک می گویم!
تبریک میگوییم، شما موفق شدید ویجتهای صفحه اصلی را برای برنامههای Flutter iOS و Android خود ایجاد کنید!
پیوند دادن به محتوا در برنامه Flutter شما
بسته به جایی که کاربر روی آن کلیک می کند، ممکن است بخواهید کاربر را به صفحه خاصی در برنامه خود هدایت کنید. به عنوان مثال، در برنامه خبری این کد لبه، ممکن است بخواهید کاربر مقاله خبری را برای عنوان نمایش داده شده ببیند.
این ویژگی خارج از محدوده این کد لبه است. میتوانید نمونههایی از استفاده از جریانی را که بسته home_widget برای شناسایی راهاندازیهای برنامه از ویجتهای صفحه اصلی و ارسال پیام از ویجت صفحه اصلی از طریق URL ارائه میکند، بیابید. برای کسب اطلاعات بیشتر، به اسناد پیوند عمیق در docs.flutter.dev مراجعه کنید.
در حال به روز رسانی ویجت خود در پس زمینه
در این لبه کد، شما با استفاده از یک دکمه، بهروزرسانی ویجت صفحه اصلی را راهاندازی کردید. اگرچه این برای آزمایش منطقی است، اما در کد تولید ممکن است بخواهید برنامه شما ویجت صفحه اصلی را در پسزمینه بهروزرسانی کند. میتوانید از افزونه workmanager برای ایجاد وظایف پسزمینه برای بهروزرسانی منابع مورد نیاز ویجت صفحه اصلی استفاده کنید. برای کسب اطلاعات بیشتر، بخش بهروزرسانی پسزمینه در بسته home_widget را بررسی کنید.
برای iOS، میتوانید از ویجت صفحه اصلی درخواست شبکه برای بهروزرسانی رابط کاربری خود را نیز بخواهید. برای کنترل شرایط یا دفعات آن درخواست، از Timeline استفاده کنید. برای کسب اطلاعات بیشتر در مورد استفاده از Timeline، به مستندات اپل "به روز نگه داشتن ویجت" مراجعه کنید.