MDC-104 ফ্লটার: উপাদান উন্নত উপাদান

1. ভূমিকা

logo_components_color_2x_web_96dp.png

মেটেরিয়াল কম্পোনেন্টস (MDC) ডেভেলপারদের ম্যাটেরিয়াল ডিজাইন বাস্তবায়নে সহায়তা করে। Google-এ প্রকৌশলী এবং UX ডিজাইনারদের একটি দল দ্বারা তৈরি, MDC কয়েক ডজন সুন্দর এবং কার্যকরী UI উপাদান বৈশিষ্ট্যযুক্ত এবং এটি Android, iOS, ওয়েব এবং Flutter.material.io/develop-এর জন্য উপলব্ধ

কোডল্যাব MDC-103- এ, আপনি আপনার অ্যাপের স্টাইল করার জন্য ম্যাটেরিয়াল কম্পোনেন্টস (MDC) এর রঙ, উচ্চতা, টাইপোগ্রাফি এবং আকৃতি কাস্টমাইজ করেছেন।

মেটেরিয়াল ডিজাইন সিস্টেমের একটি উপাদান পূর্বনির্ধারিত কাজের একটি সেট সঞ্চালন করে এবং একটি বোতামের মতো নির্দিষ্ট বৈশিষ্ট্য রয়েছে। যাইহোক, একটি বোতাম একটি ব্যবহারকারীর জন্য একটি ক্রিয়া সম্পাদন করার একটি উপায় নয়, এটি আকৃতি, আকার এবং রঙের একটি ভিজ্যুয়াল অভিব্যক্তি যা ব্যবহারকারীকে জানতে দেয় যে এটি ইন্টারেক্টিভ, এবং স্পর্শ বা ক্লিক করলে কিছু ঘটবে৷

মেটেরিয়াল ডিজাইন নির্দেশিকাগুলি ডিজাইনারের দৃষ্টিকোণ থেকে উপাদানগুলিকে বর্ণনা করে। তারা প্ল্যাটফর্ম জুড়ে উপলব্ধ মৌলিক ফাংশনগুলির একটি বিস্তৃত পরিসর এবং প্রতিটি উপাদান তৈরি করে এমন শারীরবৃত্তীয় উপাদানগুলি বর্ণনা করে। উদাহরণস্বরূপ, একটি ব্যাকড্রপে একটি পিছনের স্তর এবং এর বিষয়বস্তু, সামনের স্তর এবং এর বিষয়বস্তু, গতির নিয়ম এবং প্রদর্শনের বিকল্প রয়েছে। এই উপাদানগুলির প্রতিটি প্রতিটি অ্যাপের প্রয়োজন, ব্যবহারের ক্ষেত্রে এবং বিষয়বস্তুর জন্য কাস্টমাইজ করা যেতে পারে।

আপনি কি নির্মাণ করবেন

এই কোডল্যাবে, আপনি শ্রাইন অ্যাপের UI কে "ব্যাকড্রপ" নামে একটি দুই-স্তরের উপস্থাপনায় পরিবর্তন করবেন। পটভূমিতে একটি মেনু রয়েছে যা অপ্রতিসম গ্রিডে দেখানো পণ্যগুলিকে ফিল্টার করতে ব্যবহৃত নির্বাচনযোগ্য শ্রেণীগুলির তালিকা করে৷ এই কোডল্যাবে, আপনি নিম্নলিখিতগুলি ব্যবহার করবেন:

  • আকৃতি
  • গতি
  • ফ্লটার উইজেট (যা আপনি আগের কোডল্যাবে ব্যবহার করেছেন)

অ্যান্ড্রয়েড

iOS

গোলাপী এবং বাদামী থিমযুক্ত ই-কমার্স অ্যাপ একটি শীর্ষ অ্যাপ বার এবং একটি অপ্রতিসম, অনুভূমিকভাবে স্ক্রোলযোগ্য গ্রিড পণ্যে পূর্ণ

গোলাপী এবং বাদামী থিমযুক্ত ই-কমার্স অ্যাপ একটি শীর্ষ অ্যাপ বার এবং একটি অপ্রতিসম, অনুভূমিকভাবে স্ক্রোলযোগ্য গ্রিড পণ্যে পূর্ণ

মেনু তালিকা 4 বিভাগ

মেনু তালিকা 4 বিভাগ

এই কোডল্যাবে মেটেরিয়াল ফ্লাটার কম্পোনেন্ট এবং সাবসিস্টেম

  • আকৃতি

আপনি ফ্লটার ডেভেলপমেন্টের সাথে আপনার অভিজ্ঞতার স্তরকে কীভাবে মূল্যায়ন করবেন?

নবজাতক মধ্যবর্তী দক্ষ

2. আপনার ফ্লটার ডেভেলপমেন্ট এনভায়রনমেন্ট সেট আপ করুন

এই ল্যাবটি সম্পূর্ণ করার জন্য আপনার দুটি টুকরো সফ্টওয়্যার প্রয়োজন - ফ্লাটার SDK এবং একটি সম্পাদক

আপনি এই ডিভাইসগুলির যেকোনো একটি ব্যবহার করে কোডল্যাব চালাতে পারেন:

  • আপনার কম্পিউটারের সাথে সংযুক্ত এবং বিকাশকারী মোডে সেট করা একটি শারীরিক Android বা iOS ডিভাইস৷
  • আইওএস সিমুলেটর (এক্সকোড সরঞ্জাম ইনস্টল করা প্রয়োজন)।
  • অ্যান্ড্রয়েড এমুলেটর (অ্যান্ড্রয়েড স্টুডিওতে সেটআপ প্রয়োজন)।
  • একটি ব্রাউজার (ডিবাগিংয়ের জন্য Chrome প্রয়োজন)।
  • একটি Windows , Linux , বা macOS ডেস্কটপ অ্যাপ্লিকেশন হিসাবে। আপনি যে প্ল্যাটফর্মে স্থাপন করার পরিকল্পনা করছেন সেখানে আপনাকে অবশ্যই বিকাশ করতে হবে। সুতরাং, আপনি যদি একটি উইন্ডোজ ডেস্কটপ অ্যাপ বিকাশ করতে চান, তাহলে যথাযথ বিল্ড চেইন অ্যাক্সেস করতে আপনাকে অবশ্যই উইন্ডোজে বিকাশ করতে হবে। অপারেটিং সিস্টেম-নির্দিষ্ট প্রয়োজনীয়তা রয়েছে যা docs.flutter.dev/desktop- এ বিস্তারিতভাবে কভার করা হয়েছে।

3. কোডল্যাব স্টার্টার অ্যাপটি ডাউনলোড করুন

MDC-103 থেকে চালিয়ে যাচ্ছেন?

আপনি MDC-103 সম্পন্ন করলে, আপনার কোড এই কোডল্যাবের জন্য প্রস্তুত হওয়া উচিত। ধাপে এড়িয়ে যান: ব্যাকড্রপ মেনু যোগ করুন

স্ক্র্যাচ থেকে শুরু?

স্টার্টার অ্যাপটি material-components-flutter-codelabs-104-starter_and_103-complete/mdc_100_series ডিরেক্টরিতে অবস্থিত।

...অথবা GitHub থেকে ক্লোন করুন

GitHub থেকে এই কোডল্যাব ক্লোন করতে, নিম্নলিখিত কমান্ডগুলি চালান:

git clone https://github.com/material-components/material-components-flutter-codelabs.git
cd material-components-flutter-codelabs/mdc_100_series
git checkout 104-starter_and_103-complete

প্রকল্পটি খুলুন এবং অ্যাপটি চালান

  1. আপনার পছন্দের সম্পাদকে প্রকল্পটি খুলুন।
  2. Get Started: আপনার নির্বাচিত সম্পাদকের জন্য টেস্ট ড্রাইভ -এ "অ্যাপ চালাতে" নির্দেশাবলী অনুসরণ করুন।

সফলতার ! আপনার ডিভাইসে আগের কোডল্যাব থেকে শ্রাইন লগইন পৃষ্ঠাটি দেখতে হবে।

অ্যান্ড্রয়েড

iOS

মন্দির লগইন পৃষ্ঠা

মন্দির লগইন পৃষ্ঠা

4. ব্যাকড্রপ মেনু যোগ করুন

অন্যান্য সমস্ত সামগ্রী এবং উপাদানগুলির পিছনে একটি পটভূমি প্রদর্শিত হয়৷ এটি দুটি স্তরের সমন্বয়ে গঠিত: একটি পিছনের স্তর (যা ক্রিয়া এবং ফিল্টারগুলি প্রদর্শন করে) এবং একটি সামনের স্তর (যা সামগ্রী প্রদর্শন করে)৷ আপনি নেভিগেশন বা বিষয়বস্তু ফিল্টার মত ইন্টারেক্টিভ তথ্য এবং ক্রিয়া প্রদর্শন করতে একটি ব্যাকড্রপ ব্যবহার করতে পারেন।

হোম অ্যাপ বারটি সরান

হোমপেজ উইজেট হবে আমাদের সামনের স্তরের বিষয়বস্তু। এই মুহূর্তে এটি একটি অ্যাপ বার আছে. আমরা অ্যাপ বারটিকে পিছনের স্তরে নিয়ে যাব এবং হোমপেজে শুধুমাত্র অ্যাসিমেট্রিক ভিউ অন্তর্ভুক্ত থাকবে।

home.dart এ, শুধুমাত্র একটি AsymmetricView ফেরাতে build() ফাংশন পরিবর্তন করুন:

// TODO: Return an AsymmetricView (104)
return AsymmetricView(products: ProductsRepository.loadProducts(Category.all));

ব্যাকড্রপ উইজেট যোগ করুন

ব্যাকড্রপ নামে একটি উইজেট তৈরি করুন যাতে frontLayer এবং backLayer অন্তর্ভুক্ত থাকে।

backLayer একটি মেনু রয়েছে যা আপনাকে তালিকাটি ফিল্টার করার জন্য একটি বিভাগ নির্বাচন করতে দেয় ( currentCategory )। যেহেতু আমরা মেনু নির্বাচন অব্যাহত রাখতে চাই, তাই আমরা ব্যাকড্রপকে একটি রাষ্ট্রীয় উইজেট বানিয়ে দেব।

backdrop.dart নামে /lib এ একটি নতুন ফাইল যোগ করুন:

import 'package:flutter/material.dart';

import 'model/product.dart';

// TODO: Add velocity constant (104)

class Backdrop extends StatefulWidget {
  final Category currentCategory;
  final Widget frontLayer;
  final Widget backLayer;
  final Widget frontTitle;
  final Widget backTitle;

  const Backdrop({
    required this.currentCategory,
    required this.frontLayer,
    required this.backLayer,
    required this.frontTitle,
    required this.backTitle,
    Key? key,
  }) : super(key: key);

  @override
  _BackdropState createState() => _BackdropState();
}

// TODO: Add _FrontLayer class (104)
// TODO: Add _BackdropTitle class (104)
// TODO: Add _BackdropState class (104)

লক্ষ্য করুন আমরা required কিছু বৈশিষ্ট্য চিহ্নিত করি। এটি কনস্ট্রাক্টরের বৈশিষ্ট্যগুলির জন্য একটি সর্বোত্তম অনুশীলন যার কোনও ডিফল্ট মান নেই এবং null হতে পারে না এবং তাই ভুলে যাওয়া উচিত নয়।

ব্যাকড্রপ ক্লাস সংজ্ঞার অধীনে, _BackdropState ক্লাস যোগ করুন:

// TODO: Add _BackdropState class (104)
class _BackdropState extends State<Backdrop>
    with SingleTickerProviderStateMixin {
  final GlobalKey _backdropKey = GlobalKey(debugLabel: 'Backdrop');

  // TODO: Add AnimationController widget (104)

  // TODO: Add BuildContext and BoxConstraints parameters to _buildStack (104)
  Widget _buildStack() {
    return Stack(
    key: _backdropKey,
      children: <Widget>[
        // TODO: Wrap backLayer in an ExcludeSemantics widget (104)
        widget.backLayer,
        widget.frontLayer,
      ],
    );
  }

  @override
  Widget build(BuildContext context) {
    var appBar = AppBar(
      elevation: 0.0,
      titleSpacing: 0.0,
      // TODO: Replace leading menu icon with IconButton (104)
      // TODO: Remove leading property (104)
      // TODO: Create title with _BackdropTitle parameter (104)
      leading: Icon(Icons.menu),
      title: Text('SHRINE'),
      actions: <Widget>[
        // TODO: Add shortcut to login screen from trailing icons (104)
        IconButton(
          icon: Icon(
            Icons.search,
            semanticLabel: 'search',
          ),
          onPressed: () {
          // TODO: Add open login (104)
          },
        ),
        IconButton(
          icon: Icon(
            Icons.tune,
            semanticLabel: 'filter',
          ),
          onPressed: () {
          // TODO: Add open login (104)
          },
        ),
      ],
    );
    return Scaffold(
      appBar: appBar,
      // TODO: Return a LayoutBuilder widget (104)
      body: _buildStack(),
    );
  }
}

build() ফাংশন হোমপেজের মতোই একটি অ্যাপ বার সহ একটি স্ক্যাফোল্ড প্রদান করে। কিন্তু স্ক্যাফোল্ডের শরীর একটি স্ট্যাক । একটি স্ট্যাকের বাচ্চারা ওভারল্যাপ করতে পারে। প্রতিটি সন্তানের আকার এবং অবস্থান স্ট্যাকের পিতামাতার সাপেক্ষে নির্দিষ্ট করা হয়।

এখন ShrineApp-এ একটি ব্যাকড্রপ ইনস্ট্যান্স যোগ করুন।

app.dart এ, backdrop.dart এবং model/product.dart আমদানি করুন:

import 'backdrop.dart'; // New code
import 'colors.dart';
import 'home.dart';
import 'login.dart';
import 'model/product.dart'; // New code
import 'supplemental/cut_corners_border.dart';

app.dart, একটি Backdrop ফেরত দিয়ে / রুটটি সংশোধন করুন যার frontLayer হিসাবে HomePage রয়েছে:

// TODO: Change to a Backdrop with a HomePage frontLayer (104)
'/': (BuildContext context) => Backdrop(
     // TODO: Make currentCategory field take _currentCategory (104)
     currentCategory: Category.all,
     // TODO: Pass _currentCategory for frontLayer (104)
     frontLayer: HomePage(),
     // TODO: Change backLayer field value to CategoryMenuPage (104)
     backLayer: Container(color: kShrinePink100),
     frontTitle: Text('SHRINE'),
     backTitle: Text('MENU'),
),

আপনার প্রকল্পটি সংরক্ষণ করুন, আপনি দেখতে পাবেন যে আমাদের হোম পৃষ্ঠাটি প্রদর্শিত হচ্ছে এবং অ্যাপ বারটিও তাই:

অ্যান্ড্রয়েড

iOS

গোলাপী ব্যাকগ্রাউন্ড সহ তীর্থ পণ্য পৃষ্ঠা

গোলাপী ব্যাকগ্রাউন্ড সহ তীর্থ পণ্য পৃষ্ঠা

ব্যাকলেয়ার ফ্রন্টলেয়ার হোম পেজের পিছনে একটি নতুন স্তরে গোলাপী এলাকা দেখায়।

আপনি ফ্লাটার ইন্সপেক্টর ব্যবহার করে যাচাই করতে পারেন যে স্ট্যাকের প্রকৃতপক্ষে হোমপেজের পিছনে একটি ধারক রয়েছে। এটি এর অনুরূপ হওয়া উচিত:

92ed338a15a074bd.png

আপনি এখন উভয় স্তরের নকশা এবং বিষয়বস্তু সামঞ্জস্য করতে পারেন।

5. একটি আকৃতি যোগ করুন

এই ধাপে, আপনি উপরের বাম কোণে একটি কাটা যোগ করতে সামনের স্তরটিকে স্টাইল করবেন।

মেটেরিয়াল ডিজাইন এই ধরনের কাস্টমাইজেশনকে আকৃতি হিসেবে উল্লেখ করে। উপাদান পৃষ্ঠের নির্বিচারে আকার থাকতে পারে। আকারগুলি পৃষ্ঠগুলিতে জোর এবং শৈলী যোগ করে এবং ব্র্যান্ডিং প্রকাশ করতে ব্যবহার করা যেতে পারে। সাধারণ আয়তক্ষেত্রাকার আকারগুলি বাঁকা বা কোণীয় কোণ এবং প্রান্তগুলি এবং যে কোনও সংখ্যক পক্ষের সাথে কাস্টমাইজ করা যেতে পারে। তারা প্রতিসম বা অনিয়মিত হতে পারে।

সামনের স্তরে একটি আকৃতি যোগ করুন

কোণযুক্ত শ্রাইনের লোগোটি শ্রাইন অ্যাপের আকৃতির গল্পকে অনুপ্রাণিত করেছে। একটি আকৃতির গল্প হল আকারের সাধারণ ব্যবহার যা একটি অ্যাপ জুড়ে প্রয়োগ করা হয়। উদাহরণস্বরূপ, লগইন পৃষ্ঠার উপাদানগুলিতে লোগোর আকৃতি প্রতিধ্বনিত হয় যেগুলি আকৃতিতে প্রয়োগ করা হয়েছে। এই ধাপে, আপনি উপরের-বাম কোণে একটি কোণীয় কাটা দিয়ে সামনের স্তরটিকে স্টাইল করবেন।

backdrop.dart এ, একটি নতুন ক্লাস যোগ করুন _FrontLayer :

// TODO: Add _FrontLayer class (104)
class _FrontLayer extends StatelessWidget {
  // TODO: Add on-tap callback (104)
  const _FrontLayer({
    Key? key,
    required this.child,
  }) : super(key: key);

  final Widget child;

  @override
  Widget build(BuildContext context) {
    return Material(
      elevation: 16.0,
      shape: const BeveledRectangleBorder(
        borderRadius: BorderRadius.only(topLeft: Radius.circular(46.0)),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: <Widget>[
          // TODO: Add a GestureDetector (104)
          Expanded(
            child: child,
          ),
        ],
      ),
    );
  }
}

তারপর, _BackdropState-এর _buildStack() ফাংশনে, সামনের স্তরটিকে একটি _FrontLayer-এ মুড়ে দিন:

  Widget _buildStack() {
    // TODO: Create a RelativeRectTween Animation (104)

    return Stack(
    key: _backdropKey,
      children: <Widget>[
        // TODO: Wrap backLayer in an ExcludeSemantics widget (104)
        widget.backLayer,
        // TODO: Add a PositionedTransition (104)
        // TODO: Wrap front layer in _FrontLayer (104)
          _FrontLayer(child: widget.frontLayer),
      ],
    );
  }

পুনরায় লোড করুন।

অ্যান্ড্রয়েড

iOS

কাস্টম আকৃতি সহ মন্দির পণ্য পৃষ্ঠা

কাস্টম আকৃতি সহ মন্দির পণ্য পৃষ্ঠা

আমরা শ্রীনের প্রাথমিক পৃষ্ঠকে একটি কাস্টম আকার দিয়েছি। যাইহোক, আমরা চাই এটি দৃশ্যত অ্যাপ বারের সাথে সংযুক্ত হোক।

অ্যাপ বারের রঙ পরিবর্তন করুন

app.dart এ, _buildShrineTheme() ফাংশনটি নিম্নলিখিতগুলিতে পরিবর্তন করুন:

ThemeData _buildShrineTheme() {
  final ThemeData base = ThemeData.light(useMaterial3: true);
  return base.copyWith(
    colorScheme: base.colorScheme.copyWith(
      primary: kShrinePink100,
      onPrimary: kShrineBrown900,
      secondary: kShrineBrown900,
      error: kShrineErrorRed,
    ),
    textTheme: _buildShrineTextTheme(base.textTheme),
    textSelectionTheme: const TextSelectionThemeData(
      selectionColor: kShrinePink100,
    ),
    appBarTheme: const AppBarTheme(
      foregroundColor: kShrineBrown900,
      backgroundColor: kShrinePink100,
    ),
    inputDecorationTheme: const InputDecorationTheme(
      border: CutCornersBorder(),
      focusedBorder: CutCornersBorder(
        borderSide: BorderSide(
          width: 2.0,
          color: kShrineBrown900,
        ),
      ),
      floatingLabelStyle: TextStyle(
        color: kShrineBrown900,
      ),
    ),
  );
}

হট রিস্টার্ট। নতুন রঙিন অ্যাপ বারটি এখন উপস্থিত হওয়া উচিত।

অ্যান্ড্রয়েড

iOS

রঙিন অ্যাপ বার সহ মন্দির পণ্য পৃষ্ঠা

রঙিন অ্যাপ বার সহ মন্দির পণ্য পৃষ্ঠা

এই পরিবর্তনের কারণে, ব্যবহারকারীরা দেখতে পাচ্ছেন যে সামনের সাদা স্তরের ঠিক পিছনে কিছু আছে। চলুন গতি যোগ করি যাতে ব্যবহারকারীরা ব্যাকড্রপের পিছনের স্তরটি দেখতে পারেন।

6. গতি যোগ করুন

মোশন হল আপনার অ্যাপকে প্রাণবন্ত করার একটি উপায়। এটি বড় এবং নাটকীয়, সূক্ষ্ম এবং ন্যূনতম, বা এর মধ্যে যে কোনও জায়গায় হতে পারে। কিন্তু মনে রাখবেন যে আপনি যে ধরণের গতি ব্যবহার করবেন তা পরিস্থিতির সাথে উপযুক্ত হওয়া উচিত। বারবার, নিয়মিত ক্রিয়ায় প্রয়োগ করা গতি ছোট এবং সূক্ষ্ম হওয়া উচিত, যাতে ক্রিয়াগুলি ব্যবহারকারীকে বিভ্রান্ত না করে বা নিয়মিতভাবে খুব বেশি সময় না নেয়। কিন্তু উপযুক্ত পরিস্থিতি রয়েছে, যেমন প্রথমবার একজন ব্যবহারকারী একটি অ্যাপ খোলে, এটি আরও নজরকাড়া হতে পারে এবং কিছু অ্যানিমেশন ব্যবহারকারীকে কীভাবে আপনার অ্যাপ ব্যবহার করতে হয় সে সম্পর্কে শিক্ষিত করতে সাহায্য করতে পারে।

মেনু বোতামে রিভিল মোশন যোগ করুন

backdrop.dart এর শীর্ষে, যেকোনো শ্রেণী বা ফাংশনের সুযোগের বাইরে, আমাদের অ্যানিমেশনের যে বেগ আমরা চাই তা উপস্থাপন করতে একটি ধ্রুবক যোগ করুন:

// TODO: Add velocity constant (104)
const double _kFlingVelocity = 2.0;

_BackdropState-এ একটি অ্যানিমেশন কন্ট্রোলার উইজেট যোগ করুন, এটি initState() ফাংশনে ইনস্ট্যান্টিয়েট করুন এবং রাজ্যের dispose() ফাংশনে এটি নিষ্পত্তি করুন:

  // TODO: Add AnimationController widget (104)
  late AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(milliseconds: 300),
      value: 1.0,
      vsync: this,
    );
  }

  // TODO: Add override for didUpdateWidget (104)

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  // TODO: Add functions to get and change front layer visibility (104)

অ্যানিমেশন কন্ট্রোলার অ্যানিমেশন সমন্বয় করে এবং অ্যানিমেশন চালাতে, বিপরীত করতে এবং থামাতে আপনাকে API দেয়। এখন আমাদের এমন ফাংশন দরকার যা এটিকে সরিয়ে দেয়।

ফাংশন যোগ করুন যা নির্ধারণের পাশাপাশি সামনের স্তরটির দৃশ্যমানতা পরিবর্তন করে:

  // TODO: Add functions to get and change front layer visibility (104)
  bool get _frontLayerVisible {
    final AnimationStatus status = _controller.status;
    return status == AnimationStatus.completed ||
        status == AnimationStatus.forward;
  }

  void _toggleBackdropLayerVisibility() {
    _controller.fling(
        velocity: _frontLayerVisible ? -_kFlingVelocity : _kFlingVelocity);
  }

একটি ExcludeSemantics উইজেটে ব্যাকলেয়ার মোড়ানো। এই উইজেটটি ব্যাকলেয়ারের মেনু আইটেমগুলিকে শব্দার্থবিদ্যা গাছ থেকে বাদ দেবে যখন পিছনের স্তরটি দৃশ্যমান হবে না।

    return Stack(
      key: _backdropKey,
      children: <Widget>[
        // TODO: Wrap backLayer in an ExcludeSemantics widget (104)
        ExcludeSemantics(
          child: widget.backLayer,
          excluding: _frontLayerVisible,
        ),
      ...

BuildContext এবং BoxConstraints নিতে _buildStack() ফাংশন পরিবর্তন করুন। এছাড়াও, একটি Positioned Transition অন্তর্ভুক্ত করুন যা একটি RelativeRectTween অ্যানিমেশন নেয়:

  // TODO: Add BuildContext and BoxConstraints parameters to _buildStack (104)
  Widget _buildStack(BuildContext context, BoxConstraints constraints) {
    const double layerTitleHeight = 48.0;
    final Size layerSize = constraints.biggest;
    final double layerTop = layerSize.height - layerTitleHeight;

    // TODO: Create a RelativeRectTween Animation (104)
    Animation<RelativeRect> layerAnimation = RelativeRectTween(
      begin: RelativeRect.fromLTRB(
          0.0, layerTop, 0.0, layerTop - layerSize.height),
      end: const RelativeRect.fromLTRB(0.0, 0.0, 0.0, 0.0),
    ).animate(_controller.view);

    return Stack(
      key: _backdropKey,
      children: <Widget>[
        // TODO: Wrap backLayer in an ExcludeSemantics widget (104)
        ExcludeSemantics(
          child: widget.backLayer,
          excluding: _frontLayerVisible,
        ),
        // TODO: Add a PositionedTransition (104)
        PositionedTransition(
          rect: layerAnimation,
          child: _FrontLayer(
            // TODO: Implement onTap property on _BackdropState (104)
            child: widget.frontLayer,
          ),
        ),
      ],
    );
  }

অবশেষে, স্ক্যাফোল্ডের বডির জন্য _buildStack ফাংশন কল করার পরিবর্তে, একটি LayoutBuilder উইজেট ফেরত দিন যা _buildStack কে তার নির্মাতা হিসাবে ব্যবহার করে:

    return Scaffold(
      appBar: appBar,
      // TODO: Return a LayoutBuilder widget (104)
      body: LayoutBuilder(builder: _buildStack),
    );

আমরা LayoutBuilder ব্যবহার করে লেআউট সময় পর্যন্ত ফ্রন্ট/ব্যাক লেয়ার স্ট্যাক তৈরি করতে বিলম্ব করেছি যাতে আমরা ব্যাকড্রপের প্রকৃত সামগ্রিক উচ্চতা অন্তর্ভুক্ত করতে পারি। LayoutBuilder হল একটি বিশেষ উইজেট যার নির্মাতা কলব্যাক আকারের সীমাবদ্ধতা প্রদান করে।

build() ফাংশনে, অ্যাপ বারে লিডিং মেনু আইকনটিকে একটি আইকনবাটনে পরিণত করুন এবং বোতামটি ট্যাপ করার সময় সামনের স্তরটির দৃশ্যমানতা টগল করতে এটি ব্যবহার করুন।

      // TODO: Replace leading menu icon with IconButton (104)
      leading: IconButton(
        icon: const Icon(Icons.menu),
        onPressed: _toggleBackdropLayerVisibility,
      ),

পুনরায় লোড করুন তারপর সিমুলেটরে মেনু বোতামে আলতো চাপুন৷

অ্যান্ড্রয়েড

iOS

দুটি ত্রুটি সহ খালি মন্দির মেনু

দুটি ত্রুটি সহ খালি মন্দির মেনু

সামনের স্তর অ্যানিমেট (স্লাইড) নিচে। কিন্তু যদি আপনি নিচে তাকান, একটি লাল ত্রুটি এবং একটি ওভারফ্লো ত্রুটি আছে। এর কারণ এই অ্যানিমেশনের দ্বারা অ্যাসিমেট্রিক ভিউ চেপে যায় এবং ছোট হয়ে যায়, যা কলামগুলিতে কম জায়গা দেয়। অবশেষে, কলামগুলি প্রদত্ত স্থানের সাথে নিজেদেরকে সাজাতে পারে না এবং তারা একটি ত্রুটির কারণ হয়৷ যদি আমরা ListViews দিয়ে কলামগুলি প্রতিস্থাপন করি, তাহলে কলামের আকার যেমন অ্যানিমেট থাকবে তেমনই থাকবে।

একটি ListView মধ্যে পণ্য কলাম মোড়ানো

supplemental/product_columns.dart এ, OneProductCardColumn এর কলাম একটি ListView দিয়ে প্রতিস্থাপন করুন:

class OneProductCardColumn extends StatelessWidget {
  const OneProductCardColumn({required this.product, Key? key}) : super(key: key);

  final Product product;

  @override
  Widget build(BuildContext context) {
    // TODO: Replace Column with a ListView (104)
    return ListView(
      physics: const ClampingScrollPhysics(),
      reverse: true,
      children: <Widget>[
        ConstrainedBox(
          constraints: const BoxConstraints(
            maxWidth: 550,
          ),
          child: ProductCard(
            product: product,
          ),
        ),
        const SizedBox(
          height: 40.0,
        ),

      ],
    );
  }
}

কলামের মধ্যে রয়েছে MainAxisAlignment.end । নীচে থেকে লেআউট শুরু করতে, reverse: true । পরিবর্তনের জন্য ক্ষতিপূরণ দিতে বাচ্চাদের ক্রম বিপরীত করা হয়।

পুনরায় লোড করুন এবং মেনু বোতামটি আলতো চাপুন।

অ্যান্ড্রয়েড

iOS

একটি ত্রুটি সহ মন্দির মেনু খালি করুন৷

একটি ত্রুটি সহ মন্দির মেনু খালি করুন৷

OneProductCardColumn-এ ধূসর ওভারফ্লো সতর্কতা চলে গেছে! এখন অন্যটা ঠিক করা যাক।

supplemental/product_columns.dart এ, imageAspectRatio গণনা করার উপায় পরিবর্তন করুন এবং একটি ListView দিয়ে TwoProductCardColumn এর কলামটি প্রতিস্থাপন করুন:

      // TODO: Change imageAspectRatio calculation (104)
      double imageAspectRatio = heightOfImages >= 0.0
          ? constraints.biggest.width / heightOfImages
          : 49.0 / 33.0;
      // TODO: Replace Column with a ListView (104)
      return ListView(
        physics: const ClampingScrollPhysics(),
        children: <Widget>[
          Padding(
            padding: const EdgeInsetsDirectional.only(start: 28.0),
            child: top != null
                ? ProductCard(
                    imageAspectRatio: imageAspectRatio,
                    product: top!,
                  )
                : SizedBox(
                    height: heightOfCards,
                  ),
          ),
          const SizedBox(height: spacerHeight),
          Padding(
            padding: const EdgeInsetsDirectional.only(end: 28.0),
            child: ProductCard(
              imageAspectRatio: imageAspectRatio,
              product: bottom,
            ),
          ),
        ],
      );

আমরা imageAspectRatio এ কিছু নিরাপত্তা যোগ করেছি।

পুনরায় লোড করুন। তারপর মেনু বোতামে ট্যাপ করুন।

অ্যান্ড্রয়েড

iOS

খালি মন্দির মেনু

খালি মন্দির মেনু

আর উপচে পড়া নয়।

7. পিছনের স্তরে একটি মেনু যোগ করুন

একটি মেনু হল ট্যাপযোগ্য পাঠ্য আইটেমগুলির একটি তালিকা যা পাঠ্য আইটেমগুলি স্পর্শ করা হলে শ্রোতাদের অবহিত করে। এই ধাপে, আপনি একটি বিভাগ ফিল্টারিং মেনু যোগ করবেন।

মেনু যোগ করুন

সামনের স্তরে মেনু এবং পিছনের স্তরে ইন্টারেক্টিভ বোতাম যোগ করুন।

lib/category_menu_page.dart নামে একটি নতুন ফাইল তৈরি করুন :

import 'package:flutter/material.dart';

import 'colors.dart';
import 'model/product.dart';

class CategoryMenuPage extends StatelessWidget {
  final Category currentCategory;
  final ValueChanged<Category> onCategoryTap;
  final List<Category> _categories = Category.values;

  const CategoryMenuPage({
    Key? key,
    required this.currentCategory,
    required this.onCategoryTap,
  }) : super(key: key);

  Widget _buildCategory(Category category, BuildContext context) {
    final categoryString =
        category.toString().replaceAll('Category.', '').toUpperCase();
    final ThemeData theme = Theme.of(context);

    return GestureDetector(
      onTap: () => onCategoryTap(category),
      child: category == currentCategory
        ? Column(
            children: <Widget>[
              const SizedBox(height: 16.0),
              Text(
                categoryString,
                style: theme.textTheme.bodyLarge,
                textAlign: TextAlign.center,
              ),
              const SizedBox(height: 14.0),
              Container(
                width: 70.0,
                height: 2.0,
                color: kShrinePink400,
              ),
            ],
          )
      : Padding(
        padding: const EdgeInsets.symmetric(vertical: 16.0),
        child: Text(
          categoryString,
          style: theme.textTheme.bodyLarge!.copyWith(
              color: kShrineBrown900.withAlpha(153)
            ),
          textAlign: TextAlign.center,
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        padding: const EdgeInsets.only(top: 40.0),
        color: kShrinePink100,
        child: ListView(
          children: _categories
            .map((Category c) => _buildCategory(c, context))
            .toList()),
      ),
    );
  }
}

এটি একটি অঙ্গভঙ্গি ডিটেক্টর একটি কলাম মোড়ানো যার শিশুদের বিভাগের নাম। নির্বাচিত বিভাগ নির্দেশ করতে একটি আন্ডারলাইন ব্যবহার করা হয়।

app.dart এ, ShrineApp উইজেটকে স্টেটলেস থেকে স্টেটফুল-এ রূপান্তর করুন।

  1. ShrineApp.
  2. আপনার IDE এর উপর ভিত্তি করে, কোড ক্রিয়া দেখান:
  3. অ্যান্ড্রয়েড স্টুডিও: ⌥Enter (macOS) বা alt + enter টিপুন
  4. VS কোড: ⌘ টিপুন। (macOS) বা Ctrl+।
  5. "Convert to StatefulWidget" নির্বাচন করুন।
  6. ShrineAppState ক্লাসকে ব্যক্তিগত (_ShrineAppState) এ পরিবর্তন করুন। ShrineAppState রাইট-ক্লিক করুন, এবং
  7. অ্যান্ড্রয়েড স্টুডিও: রিফ্যাক্টর > পুনঃনামকরণ নির্বাচন করুন
  8. VS কোড: Rename Symbol নির্বাচন করুন
  9. ক্লাসটিকে ব্যক্তিগত করতে _ShrineAppState লিখুন।

app.dart এ, নির্বাচিত বিভাগের জন্য _ShrineAppState এ একটি ভেরিয়েবল যোগ করুন এবং এটি ট্যাপ করা হলে একটি কলব্যাক করুন:

class _ShrineAppState extends State<ShrineApp> {
  Category _currentCategory = Category.all;

  void _onCategoryTap(Category category) {
    setState(() {
      _currentCategory = category;
    });
  }

তারপরে পিছনের স্তরটিকে একটি CategoryMenuPage এ পরিবর্তন করুন।

app.dart এ, CategoryMenuPage ইম্পোর্ট করুন:

import 'backdrop.dart';
import 'category_menu_page.dart';
import 'colors.dart';
import 'home.dart';
import 'login.dart';
import 'model/product.dart';
import 'supplemental/cut_corners_border.dart';

build() ফাংশনে, ইনস্ট্যান্স ভেরিয়েবল নিতে ব্যাকলেয়ার ক্ষেত্রটি CategoryMenuPage এবং বর্তমান ক্যাটাগরি ফিল্ডে পরিবর্তন করুন।

'/': (BuildContext context) => Backdrop(
              // TODO: Make currentCategory field take _currentCategory (104)
              currentCategory: _currentCategory,
              // TODO: Pass _currentCategory for frontLayer (104)
              frontLayer: HomePage(),
              // TODO: Change backLayer field value to CategoryMenuPage (104)
              backLayer: CategoryMenuPage(
                currentCategory: _currentCategory,
                onCategoryTap: _onCategoryTap,
              ),
              frontTitle: const Text('SHRINE'),
              backTitle: const Text('MENU'),
            ),

পুনরায় লোড করুন এবং মেনু বোতামটি আলতো চাপুন।

অ্যান্ড্রয়েড

iOS

4টি বিভাগ সহ মন্দির মেনু

4টি বিভাগ সহ মন্দির মেনু

আপনি যদি একটি মেনু বিকল্পে ট্যাপ করেন তবে কিছুই হবে না...এখনও। এর ঠিক করা যাক.

home.dart এ, Category-এর জন্য একটি ভেরিয়েবল যোগ করুন এবং এটি AsymmetricView-এ পাস করুন।

import 'package:flutter/material.dart';

import 'model/product.dart';
import 'model/products_repository.dart';
import 'supplemental/asymmetric_view.dart';

class HomePage extends StatelessWidget {
  // TODO: Add a variable for Category (104)
  final Category category;

  const HomePage({this.category = Category.all, Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // TODO: Pass Category variable to AsymmetricView (104)
    return AsymmetricView(
      products: ProductsRepository.loadProducts(category),
    );
  }
}

app.dart এ, frontLayer এর জন্য _currentCategory পাস করুন:।

// TODO: Pass _currentCategory for frontLayer (104)
frontLayer: HomePage(category: _currentCategory),

পুনরায় লোড করুন। সিমুলেটরে মেনু বোতামে আলতো চাপুন এবং একটি বিভাগ নির্বাচন করুন।

অ্যান্ড্রয়েড

iOS

তীর্থ ফিল্টার পণ্য পাতা

তীর্থ ফিল্টার পণ্য পাতা

তারা ফিল্টার করছি!

একটি মেনু নির্বাচনের পরে সামনের স্তরটি বন্ধ করুন

backdrop.dart এ, _BackdropState-এ didUpdateWidget() (যখনই উইজেট কনফিগারেশন পরিবর্তন হয় তখন বলা হয়) ফাংশনের জন্য একটি ওভাররাইড যোগ করুন:

  // TODO: Add override for didUpdateWidget() (104)
  @override
  void didUpdateWidget(Backdrop old) {
    super.didUpdateWidget(old);

    if (widget.currentCategory != old.currentCategory) {
      _toggleBackdropLayerVisibility();
    } else if (!_frontLayerVisible) {
      _controller.fling(velocity: _kFlingVelocity);
    }
  }

একটি হট রিলোড ট্রিগার করতে আপনার প্রকল্প সংরক্ষণ করুন. মেনু আইকনে আলতো চাপুন এবং একটি বিভাগ নির্বাচন করুন। মেনুটি স্বয়ংক্রিয়ভাবে বন্ধ হওয়া উচিত এবং আপনি নির্বাচিত আইটেমগুলির বিভাগ দেখতে পাবেন। এখন আপনি সামনের স্তরেও সেই কার্যকারিতা যোগ করবেন।

সামনের স্তরটি টগল করুন

backdrop.dart এ, ব্যাকড্রপ স্তরে একটি অন-ট্যাপ কলব্যাক যোগ করুন:

class _FrontLayer extends StatelessWidget {
  // TODO: Add on-tap callback (104)
  const _FrontLayer({
    Key? key,
    this.onTap, // New code
    required this.child,
  }) : super(key: key);
 
  final VoidCallback? onTap; // New code
  final Widget child;

তারপর _FrontLayer's child: Column's Children: এ একটি GestureDetector যোগ করুন।

      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: <Widget>[
          // TODO: Add a GestureDetector (104)
          GestureDetector(
            behavior: HitTestBehavior.opaque,
            onTap: onTap,
            child: Container(
              height: 40.0,
              alignment: AlignmentDirectional.centerStart,
            ),
          ),
          Expanded(
            child: child,
          ),
        ],
      ),

তারপরে _buildStack() ফাংশনে _BackdropState-এ নতুন onTap সম্পত্তি প্রয়োগ করুন:

          PositionedTransition(
            rect: layerAnimation,
            child: _FrontLayer(
              // TODO: Implement onTap property on _BackdropState (104)
              onTap: _toggleBackdropLayerVisibility,
              child: widget.frontLayer,
            ),
          ),

পুনরায় লোড করুন এবং সামনের স্তরের শীর্ষে আলতো চাপুন৷ আপনি যখনই সামনের স্তরের শীর্ষে ট্যাপ করবেন তখন স্তরটি খোলা এবং বন্ধ হওয়া উচিত।

8. একটি ব্র্যান্ডেড আইকন যোগ করুন

ব্র্যান্ডেড আইকনোগ্রাফি পরিচিত আইকনগুলিতেও প্রসারিত। আসুন একটি অনন্য, ব্র্যান্ডেড চেহারার জন্য প্রকাশ আইকনটিকে কাস্টম তৈরি করি এবং এটিকে আমাদের শিরোনামের সাথে একীভূত করি৷

মেনু বোতাম আইকন পরিবর্তন করুন

অ্যান্ড্রয়েড

iOS

ব্র্যান্ডেড আইকন সহ শ্রাইন পণ্য পৃষ্ঠা

ব্র্যান্ডেড আইকন সহ শ্রাইন পণ্য পৃষ্ঠা

backdrop.dart এ, একটি নতুন ক্লাস _BackdropTitle তৈরি করুন।

// TODO: Add _BackdropTitle class (104)
class _BackdropTitle extends AnimatedWidget {
  final void Function() onPress;
  final Widget frontTitle;
  final Widget backTitle;

  const _BackdropTitle({
    Key? key,
    required Animation<double> listenable,
    required this.onPress,
    required this.frontTitle,
    required this.backTitle,
  }) : _listenable = listenable, 
       super(key: key, listenable: listenable);

  final Animation<double> _listenable;

  @override
  Widget build(BuildContext context) {
    final Animation<double> animation = _listenable;

    return DefaultTextStyle(
      style: Theme.of(context).textTheme.titleLarge!,
      softWrap: false,
      overflow: TextOverflow.ellipsis,
      child: Row(children: <Widget>[
        // branded icon
        SizedBox(
          width: 72.0,
          child: IconButton(
            padding: const EdgeInsets.only(right: 8.0),
            onPressed: this.onPress,
            icon: Stack(children: <Widget>[
              Opacity(
                opacity: animation.value,
                child: const ImageIcon(AssetImage('assets/slanted_menu.png')),
              ),
              FractionalTranslation(
                translation: Tween<Offset>(
                  begin: Offset.zero,
                  end: const Offset(1.0, 0.0),
                ).evaluate(animation),
                child: const ImageIcon(AssetImage('assets/diamond.png')),
              )]),
          ),
        ),
        // Here, we do a custom cross fade between backTitle and frontTitle.
        // This makes a smooth animation between the two texts.
        Stack(
          children: <Widget>[
            Opacity(
              opacity: CurvedAnimation(
                parent: ReverseAnimation(animation),
                curve: const Interval(0.5, 1.0),
              ).value,
              child: FractionalTranslation(
                translation: Tween<Offset>(
                  begin: Offset.zero,
                  end: const Offset(0.5, 0.0),
                ).evaluate(animation),
                child: backTitle,
              ),
            ),
            Opacity(
              opacity: CurvedAnimation(
                parent: animation,
                curve: const Interval(0.5, 1.0),
              ).value,
              child: FractionalTranslation(
                translation: Tween<Offset>(
                  begin: const Offset(-0.25, 0.0),
                  end: Offset.zero,
                ).evaluate(animation),
                child: frontTitle,
              ),
            ),
          ],
        )
      ]),
    );
  }
}

_BackdropTitle হল একটি কাস্টম উইজেট যা AppBar উইজেটের title প্যারামিটারের জন্য প্লেইন Text উইজেটকে প্রতিস্থাপন করবে। এটিতে একটি অ্যানিমেটেড মেনু আইকন এবং সামনে এবং পিছনের শিরোনামের মধ্যে অ্যানিমেটেড রূপান্তর রয়েছে। অ্যানিমেটেড মেনু আইকন একটি নতুন সম্পদ ব্যবহার করবে। নতুন slanted_menu.png এর রেফারেন্স অবশ্যই pubspec.yaml এ যোগ করতে হবে।

assets:
    - assets/diamond.png
    # TODO: Add slanted menu asset (104)
    - assets/slanted_menu.png
    - packages/shrine_images/0-0.jpg

AppBar নির্মাতার মধ্যে leading সম্পত্তি সরান. কাস্টম ব্র্যান্ডেড আইকনটি মূল leading উইজেটের জায়গায় রেন্ডার করার জন্য অপসারণ করা প্রয়োজন৷ ব্র্যান্ডেড আইকনের জন্য অ্যানিমেশন listenable এবং onPress হ্যান্ডলার _BackdropTitle এ পাঠানো হয়। frontTitle এবং backTitle পাস করা হয়েছে যাতে সেগুলি ব্যাকড্রপ শিরোনামের মধ্যে রেন্ডার করা যায়। AppBar এর title পরামিতি এই মত হওয়া উচিত:

// TODO: Create title with _BackdropTitle parameter (104)
title: _BackdropTitle(
  listenable: _controller.view,
  onPress: _toggleBackdropLayerVisibility,
  frontTitle: widget.frontTitle,
  backTitle: widget.backTitle,
),

ব্র্যান্ডেড আইকনটি _BackdropTitle. এটিতে অ্যানিমেটেড আইকনগুলির একটি Stack রয়েছে: একটি তির্যক মেনু এবং একটি হীরা, যা একটি IconButton মোড়ানো থাকে যাতে এটি টিপতে পারে। অনুভূমিক আইকন গতির জন্য জায়গা তৈরি করতে IconButton তারপরে একটি SizedBox মোড়ানো হয়।

ফ্লটারের "সবকিছুই একটি উইজেট" আর্কিটেকচার সম্পূর্ণ নতুন কাস্টম AppBar উইজেট তৈরি না করেই ডিফল্ট AppBar বিন্যাস পরিবর্তন করতে দেয়। title প্যারামিটার, যা মূলত একটি Text উইজেট, আরও জটিল _BackdropTitle দিয়ে প্রতিস্থাপিত হতে পারে। যেহেতু _BackdropTitle কাস্টম আইকনও রয়েছে, তাই এটি leading সম্পত্তির জায়গা নেয়, যা এখন বাদ দেওয়া যেতে পারে। এই সহজ উইজেট প্রতিস্থাপন অন্য কোনো প্যারামিটার পরিবর্তন না করেই সম্পন্ন করা হয়, যেমন অ্যাকশন আইকন, যা তাদের নিজের কাজ চালিয়ে যায়।

লগইন স্ক্রিনে ফিরে একটি শর্টকাট যোগ করুন

backdrop.dart, অ্যাপ বারে দুটি ট্রেইলিং আইকন থেকে লগইন স্ক্রিনে ফিরে একটি শর্টকাট যোগ করুন: আইকনগুলির নতুন উদ্দেশ্য প্রতিফলিত করতে তাদের শব্দার্থিক লেবেলগুলি পরিবর্তন করুন৷

        // TODO: Add shortcut to login screen from trailing icons (104)
        IconButton(
          icon: const Icon(
            Icons.search,
            semanticLabel: 'login', // New code
          ),
          onPressed: () {
            // TODO: Add open login (104)
            Navigator.push(
              context,
              MaterialPageRoute(
                builder: (BuildContext context) => LoginPage()),
            );
          },
        ),
        IconButton(
          icon: const Icon(
            Icons.tune,
            semanticLabel: 'login', // New code
          ),
          onPressed: () {
            // TODO: Add open login (104)
            Navigator.push(
              context,
              MaterialPageRoute(
                builder: (BuildContext context) => LoginPage()),
            );
          },
        ),

আপনি যদি পুনরায় লোড করার চেষ্টা করেন তবে আপনি একটি ত্রুটি পাবেন৷ ত্রুটি ঠিক করতে login.dart আমদানি করুন:

import 'login.dart';

অ্যাপটি পুনরায় লোড করুন এবং লগইন স্ক্রিনে ফিরে যেতে অনুসন্ধান বা টিউন বোতামগুলি আলতো চাপুন৷

9. অভিনন্দন!

এই চারটি কোডল্যাব চলাকালীন, আপনি ব্র্যান্ডের ব্যক্তিত্ব এবং শৈলীকে প্রকাশ করে এমন অনন্য, মার্জিত ব্যবহারকারীর অভিজ্ঞতা তৈরি করতে উপাদান উপাদানগুলি কীভাবে ব্যবহার করবেন তা শিখেছেন।

পরবর্তী পদক্ষেপ

এই কোডল্যাব, MDC-104, কোডল্যাবগুলির এই ক্রমটি সম্পূর্ণ করে। আপনি ম্যাটেরিয়াল কম্পোনেন্টস উইজেট ক্যাটালগ পরিদর্শন করে ম্যাটেরিয়াল ফ্লাটারে আরও বেশি উপাদান অন্বেষণ করতে পারেন।

প্রসারিত লক্ষ্যের জন্য, ব্র্যান্ডেড আইকনটিকে একটি অ্যানিমেটেড আইকন দিয়ে প্রতিস্থাপন করার চেষ্টা করুন যা দুটি আইকনের মধ্যে অ্যানিমেট হয় যখন ব্যাকড্রপ দৃশ্যমান হয়৷

আপনার আগ্রহের উপর ভিত্তি করে আপনার চেষ্টা করার জন্য প্রচুর অন্যান্য ফ্লটার কোডল্যাব রয়েছে। আমাদের কাছে অন্য একটি উপাদান-নির্দিষ্ট কোডল্যাব রয়েছে যা আপনি আগ্রহী হতে পারেন: ফ্লাটারের জন্য উপাদান গতির সাথে সুন্দর রূপান্তর তৈরি করা

আমি যুক্তিসঙ্গত সময় এবং প্রচেষ্টার সাথে এই কোডল্যাবটি সম্পূর্ণ করতে সক্ষম হয়েছি

দৃঢ়ভাবে একমত একমত নিরপেক্ষ অসম্মতি দৃঢ়ভাবে অসম্মতি

আমি ভবিষ্যতে উপাদান উপাদান ব্যবহার চালিয়ে যেতে চাই

দৃঢ়ভাবে একমত একমত নিরপেক্ষ অসম্মতি দৃঢ়ভাবে অসম্মতি