شرح NestedScrollView وانشاء واجهة profile تطبيق instagram في Flutter
في هذا المقال سوف نشرح معكم كيفية استخدام NestedScrollView في تطوير تطبيقات Flutter حيث ان NestedScrollView من الامور المهمه التي عليك معرفتها لانها ترفع من كفاءة التطبيق الخاص بك بشكل كبير جدا وابسط مثال على ذلك عندما تريد ان تقوم بعمل تحريك كامل للشاشه في طبيعة الحال تستخدم Single scroll ولكن لو تلاحظ ان الاداء الخاص بتطبيقك يقل ولهذا ليس بالامر الصحيح استخدامها في كل المواضيع والسبب ولكن المشكلة ان يكون لديك list اسفل مجموعه عناصر وتريد عمل scroll للصفحه بشكل كامل فالحل الافضل لك هو استخدام NestedScrollView كما سوف نتعرف عليها اليوم في هذا المقال وهيا مهمه جدا جدا في تطوير تطبيقات الاندرويد و تطبيقات ios .
يمكنك مشاركة تطبيقات الويب بسرعة مع أصدقائك وزملائك في العمل. من خلال البريد الإلكتروني أو منصات الوسائط الاجتماعية مثل Facebook أو Twitter ، يمكنك مشاركة الروابط معهم. يسهل الوصول إليها من أي مكان وفي أي وقت لأنها متوفرة عبر العديد من الأنظمة الأساسية والمتصفحات. مرونة قابلة للتطوير أكبر ميزة لتطوير تطبيق ويب هي أنه يمكنك تحديث موقع الويب الخاص بك أو تعديله وقتما تشاء. يمكنك تغيير المواد وإضافة الميزات أو حذفها والمزيد. سواء كنت تدير شركة صغيرة أو متجرًا عبر الإنترنت ، يمكنك دائمًا تحديث موقع الويب الخاص بك بميزات ووظائف جديدة لتلبية احتياجاتك.
إنشاء جزء البيانات الشخصيه في تطبيق انستغرام داخل flutter
هذا الجزء مسؤول عن انشاء الجزء العلوي للتطبيق والذي سوف يكون عباره عن عدد المتابعين والمتابعه والصورة الشخصيه وعدد منشوراتك وال bio فقط هذا يكون عباره عن design في تطبيقك .
profile.dart
class ProfileView extends StatelessWidget {
const ProfileView({super.key});
@override
Widget build(BuildContext context) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
children: [
Container(
height: 80,
width: 80,
decoration: const BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(
image: AssetImage(
'assets/img/icon/category_4.png'
),
)
),
),
Container(
margin: const EdgeInsets.only(left: 16),
child: RichText(
text: const TextSpan(
children: [
TextSpan(
text: 'Dev Clips',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 16
)
),
TextSpan(
text: '\nFlutter Demo\nFlutter Web\nFlutter Linux',
style: TextStyle(
color: Colors.black87,
fontSize: 14
)
)
]
),
),
),
],
),
Expanded(child: Container(
margin: const EdgeInsets.symmetric(vertical: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text(
'30',
style: TextStyle(
fontSize: 16,
color: Colors.black,
fontWeight: FontWeight.bold
),
),
SizedBox(
height: 20,
),
Text(
'Posts'
)
],
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text(
'130k',
style: TextStyle(
fontSize: 16,
color: Colors.black,
fontWeight: FontWeight.bold
),
),
SizedBox(
height: 20,
),
Text(
'Followers'
)
],
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text(
'130k',
style: TextStyle(
fontSize: 16,
color: Colors.black,
fontWeight: FontWeight.bold
),
),
SizedBox(
height: 20,
),
Text(
'Following'
)
],
),
],
),
),),
],
);
}
}
إنشاء عارض الصور في Flutter لعرض مجموعة الصور والتحريك بينهم
في هذا الجزء استخدمنا NestedScrollView من اجل تحريك التصميم بشكل كامل لو تلاحظ انها ترجع لنا headerSliverBuilder وهو الجزء الموجود بالاعلى وهنا قمنا بعمل appbar وتصميم الصفحة الذي قمنا به في الاعلى واسفلها body وهو التصميم الذي سوف يعرض وهنا قمنا بعمل list من نوع grid لعرض ثلاث عناصر بجانب بعض كما هو موضح وهذا سوف يمكننا من عمل scrolling للصفحه بشكل كامل دون ان يقل معنا اداء التطبيق وسوف يعمل بقوة عاليه كما تعودنا عليه .
items.dart
class MyMobileBody extends StatefulWidget {
const MyMobileBody({Key? key}) : super(key: key);
@override
State<MyMobileBody> createState() => _MyMobileBodyState();
}
class _MyMobileBodyState extends State<MyMobileBody> with TickerProviderStateMixin{
static const List<String> posts = [
'assets/img/background/image-5.png',
'assets/img/background/image-4.jpg',
'assets/img/background/image-3.jpg',
'assets/img/map/avatar-1.png',
'assets/img/map/avatar-3.png',
'assets/img/map/avatar-5.png',
];
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: DefaultTabController(
length: 3,
child: NestedScrollView(
physics: const NeverScrollableScrollPhysics(),
headerSliverBuilder: (context,isScolled){
return [
SliverAppBar(
backgroundColor: Colors.white,
collapsedHeight: MediaQuery.of(context).size.height * 0.25,
expandedHeight: MediaQuery.of(context).size.height * 0.25,
flexibleSpace: ProfileView(),
),
SliverPersistentHeader(
delegate: MyDelegate(
const TabBar(
tabs: [
Tab(icon: Icon(Icons.grid_on)),
Tab(icon: Icon(Icons.favorite_border_outlined)),
Tab(icon: Icon(Icons.bookmark_border)),
],
indicatorColor: Colors.blue,
unselectedLabelColor: Colors.grey,
labelColor: Colors.black,
)
),
floating: true,
pinned: true,
)
];
},
body: TabBarView(
children: [1,2,3].map((tab) =>
GridView.count(
physics: const BouncingScrollPhysics(),
crossAxisCount: 3,
shrinkWrap: true,
mainAxisSpacing: 2.0,
crossAxisSpacing: 2.0,
children: posts.map((e) =>
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
e
),
fit: BoxFit.fill
)
),
)
).toList(),
)
).toList(),
),
),
),
),
);
}
}
class MyDelegate extends SliverPersistentHeaderDelegate{
MyDelegate(this.tabBar);
final TabBar tabBar;
@override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
return Container(
color: Colors.white,
child: tabBar,
);
}
// before scroll
@override
double get maxExtent => tabBar.preferredSize.height;
// after scroll
@override
double get minExtent => tabBar.preferredSize.height;
@override
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) {
return false;
}
}