<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>متریال_دیزاین - اندروید استودیو</title>
	<atom:link href="https://android-studio.ir/tag/%D9%85%D8%AA%D8%B1%DB%8C%D8%A7%D9%84_%D8%AF%DB%8C%D8%B2%D8%A7%DB%8C%D9%86/feed/" rel="self" type="application/rss+xml" />
	<link>https://android-studio.ir/tag/متریال_دیزاین/</link>
	<description>آموزش برنامه نویسی اندروید</description>
	<lastBuildDate>Thu, 13 Apr 2023 12:40:09 +0000</lastBuildDate>
	<language>fa-IR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	
	<item>
		<title>راست چین کردن Toolbar متریال اندروید</title>
		<link>https://android-studio.ir/android-toolbar-rtl-support/</link>
					<comments>https://android-studio.ir/android-toolbar-rtl-support/#comments</comments>
		
		<dc:creator><![CDATA[سیدمهدی مطهری]]></dc:creator>
		<pubDate>Thu, 09 May 2019 02:27:00 +0000</pubDate>
				<category><![CDATA[آموزش‌های پایه]]></category>
		<category><![CDATA[آموزش‌های رایگان]]></category>
		<category><![CDATA[رابط_کاربری]]></category>
		<category><![CDATA[رابط_کاربری_اندروید]]></category>
		<category><![CDATA[راست_چین]]></category>
		<category><![CDATA[متریال_دیزاین]]></category>
		<guid isPermaLink="false">https://android-studio.ir/?p=157317</guid>

					<description><![CDATA[<p>به نام خدا. در مبحث آموزش ساخت Toolbar با نحوه پیاده سازی تولبار در پروژه اندرویدی آشنا شدیم. در این قسمت از آموزش برنامه نویسی اندروید نحوه‌ی راست چین کردن Toolbar در اندروید را بررسی می‌کنیم. ضرورت راست چین کردن اجزای رابط کاربری اندروید مخاطبان برنامه‌های اندرویدی که شما به عنوان یک توسعه دهنده منتشر [&#8230;]</p>
<p>نوشته <a href="https://android-studio.ir/android-toolbar-rtl-support/">راست چین کردن Toolbar متریال اندروید</a> اولین بار در <a href="https://android-studio.ir">اندروید استودیو</a> پدیدار شد.</p>
]]></description>
										<content:encoded><![CDATA[<p>به نام خدا. در مبحث <a href="http://android-studio.ir/android-toolbar-actionbar/">آموزش ساخت Toolbar</a> با نحوه پیاده سازی تولبار در پروژه اندرویدی آشنا شدیم. در این قسمت از <a href="http://android-studio.ir/">آموزش برنامه نویسی اندروید</a> نحوه‌ی راست چین کردن Toolbar در اندروید را بررسی می‌کنیم.</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/rtltoolbar/left-to-right-android-material-toolbar.png" alt="تولبار چپ چین LTR در اندروید" /><br />
<img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/rtltoolbar/right-to-left-android-material-toolbar.png" alt="راست چین کردن Toolbar در اندروید" /></p>
<h2>ضرورت راست چین کردن اجزای رابط کاربری اندروید</h2>
<p>مخاطبان برنامه‌های اندرویدی که شما به عنوان یک توسعه دهنده منتشر می‌کنید عمدتا فارسی زبان هستند بنابراین لازم است چینش محتوا و قسمت‌های مختلف اپلیکیشن برای یک کاربر فارسی زبان بهینه سازی شده باشد.<br />
مفاهیمی مانند راست چین (Right to left یا به اختصار RTL) و چپ چین (Left to right یا LTR) محدود به اپلیکیشن‌های موبایلی نبوده و حتما در سایر محیط‌های نرم افزاری با این اصطلاحات آشنا شده‌اید. به عنوان مثال در یک ویراستار متن مانند Office Word یا صفحات وب نیز این مفاهیم به کار گرفته شده‌اند. اگر با طراحی صفحات وب آشنایی داشته باشید احتمالا می‌دانید در CSS با تعریف direction:rtl تمامی محتوای موجود در صفحه راست چین می‌شود.</p>
<h2>راست چین کردن تولبار در اندروید</h2>
<p>در این آموزش به بررسی روش‌های راست چین کردن Toolbar در اندروید می‌پردازیم. برای این مبحث پروژه‌ی جدیدی نمی‌سازم و همان پروژه <a href="http://android-studio.ir/android-toolbar-actionbar/">آموزش ساخت Toolbar</a> را ویرایش می‌کنم تا نتیجه کار نیز برای شما بهتر قابل درک باشد.<br />
اندروید در API 17 یا همان Android 4.2 (Jelly Bean) و همچنین API 19  یا Android 4.4 (KITKAT) قابلیت پشتیبانی از Layout های راست به چپ (RTL Layout) را به سیستم عامل خود اضافه کرد. با معرفی این قابلیت، راه برای توسعه دهندگان اندروید تا حدود زیادی هموار شد. تا پیش از این برای راست چین کردن تولبار لازم بود تولبار کاملا به صورت دستی پیاده سازی شود. اما از API 17 به سادگی می‌توان راست چین کردن تولبار و View های اندروید را انجام داد.<br />
راست چین کردن Toolbar در اندروید را به دو صورت آموزش می‌دهم. روش نخست با استفاده از خاصیت layoutDirection در XML و روش دوم استفاده از متد setLayoutDirection در Java.</p>
<h3>۱: راست چین کردن Toolbar توسط خاصیت layoutDirection در XML</h3>
<p>این روش برای دیوایس‌های با API 17 و به بالا سازگاری دارد. قبل از هرچیز باید مطمئن شویم پروژه اندروید ما از قابلیت RTL پشتیبانی می‌کند. فعال شدن پشتیبانی از زبان‌های راست به چپ در اندروید توسط خاصیت android:supportsRtl در فایل مانیفست صورت می‌گیرد. فایل AndroidManifest.xml پروژه را باز می‌کنم:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;manifest xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    package=&quot;ir.android_studio.toolbar&quot;&gt;

    &lt;application
        android:allowBackup=&quot;true&quot;
        android:icon=&quot;@mipmap/ic_launcher&quot;
        android:label=&quot;@string/app_name&quot;
        android:roundIcon=&quot;@mipmap/ic_launcher_round&quot;
        android:supportsRtl=&quot;true&quot;
        android:theme=&quot;@style/AppTheme&quot;&gt;
        &lt;activity android:name=&quot;.MainActivity&quot;&gt;
            &lt;intent-filter&gt;
                &lt;action android:name=&quot;android.intent.action.MAIN&quot; /&gt;

                &lt;category android:name=&quot;android.intent.category.LAUNCHER&quot; /&gt;
            &lt;/intent-filter&gt;
        &lt;/activity&gt;
    &lt;/application&gt;

&lt;/manifest&gt;
</pre>
<p>مشاهده می‌کنید این خاصیت در تگ application با مقدار true قرار دارد بنابراین درون مانیفست لازم نیست کار دیگری انجام دهم. اگر این تگ در مانیفست شما وجود ندارد آنرا اضافه کرده یا در صورتی که مقدار آن false است به true تغییر دهید.<br />
پروژه را اجرا می‌کنم:<br />
<img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/rtltoolbar/add_supportsRtl_attribute_to_androidManifest.png" alt="خاصیت supportsRtl پشتیبانی از زبان‌های راست چین در برنامه نویسی اندروید" /><br />
هنوز تغییری در تولبار صورت نگرفته و چینش در حالت LTR است. </p>
<div class="alert alert-warning">
<span class="notice">نکته:</span> در صورتی که زبان دیوایس اندرویدی کاربر یکی از زبان‌های راست به چپ مانند فارسی باشد، صرف وجود android:supportsRtl=”true” در مانیفست باعث تغییر چینش اجزاء به صورت راست چین می‌شود. با اینحال عده زیادی از کاربران فارسی زبان (از جمله خودم) بنا به دلایلی با زبان انگلیسی در محیط سیستم عامل راحتتر هستیم. بنابراین در صورتی که به خاصیت فوق اکتفا کنیم بازهم بخش عمده ای از مخاطبان فارسی زبان، اپلیکیشن ما را به صورت غیر استاندارد مشاهده خواهند کرد و لازم است مراحل بعد را هم دنبال کنیم.
</div>
<p>فایل activity_main.xml را باز کرده و خاصیت layoutDirection را با مقدار rtl به Toolbar اضافه می‌کنم:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;android.support.v7.widget.Toolbar
   android:layout_width=&quot;match_parent&quot;
   android:layout_height=&quot;?attr/actionBarSize&quot;
   android:id=&quot;@+id/m_toolbar&quot;
   android:background=&quot;?attr/colorPrimary&quot;
   android:elevation=&quot;3dp&quot;
   android:theme=&quot;@style/ToolbarTheme&quot;
   app:popupTheme=&quot;@style/ThemeOverlay.AppCompat.Dark&quot;
   android:layoutDirection=&quot;rtl&quot;/&gt;
</pre>
<p>با اجرای مجدد پروژه تولبار راست چین می‌شود:<br />
<img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/rtltoolbar/rtl_android_toolbar_using_layoutDirection_attribute.png" alt="راست چین کردن تولبار توسط خاصیت layoutDirection در اندروید" /><br />
آیتم‌هایی که در سمت چپ تولبار قرار داشت به سمت راست منتقل شدند و بلعکس. حتی آیتم‌های منوی تولبار نیز راست چین شده است:<br />
<img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/rtltoolbar/rtl_toolbar_menu_items.png" alt="راست چین کردن آیتم‌های منوی Toolbar در اندروید" /></p>
<div class="alert alert-warning">
<span class="notice">نکته:</span> عنوان پروژه و آیتم‌های منو را با کلمات فارسی جایگزین کردم تا خروجی کار برای شما واضح باشد.
</div>
<div class="alert alert-warning">
<span class="notice">نکته:</span> layoutDirection محدود به یک View، Widget یا Layout خاص نیست و در همه‌جا می‌توان استفاده کرد. در همین اکتیویتی می‌توانستم بجای اضافه کردن این خاصیت به Toolbar آنرا به لایه‌ی اصلی اکتیویتی که از نوع LinearLayout هست اضافه کنم. به این ترتیب تمامی عناصر موجود درون این لایه راست چین می‌شوند. از جمله TextView ای که عبارت Hello World را نمایش می‌دهد:<br />
<img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/rtltoolbar/rtl_android_layout_using_layoutDirection_attribute.png" alt="راست چین کردن layout توسط layoutDirection در برنامه نویسی اندروید" />
</div>
<h3>۲: راست چین کردن تولبار توسط متد setLayoutDirection </h3>
<p>این روش برای دیوایس‌های با API 19 و به بالا سازگاری دارد. در این روش نیز مانند قبل ابتدا باید خاصیت android:supportsRtl با مقدار true در مانیفست پروژه اندروید تعریف شده باشد.<br />
خاصیت android:layoutDirection که در مرحله قبل به تولبار یا لایه‌ی اصلی اکتیویتی اضافه شده را حذف می‌کنم.<br />
سپس خط کد زیر را داخل متد onCreate اکتیویتی اضافه می‌کنم:</p>
<pre class="brush: java; title: ; notranslate">
getWindow().getDecorView().setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
</pre>
<p>پارامتر ورودی متد setLayoutDirection از نوع View.LAYOUT_DIRECTION_RTL است که از نام آن پیداست که Direction (جهت) چینش اجزای Layout از نوع RTL اعمال می‌شود.<br />
پروژه تولبار فقط یک اکتیویتی دارد بنابراین این خط درون MainActivity قرار می‌گیرد.<br />
پروژه را اجرا می‌کنم:<br />
<img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/rtltoolbar/rtl_android_layout_using_setLayoutDirection_method.png" alt="راست چین کردن تولبار توسط متد setLayoutDirection در اندروید" /><br />
مانند حالتی که در مرحله قبل android:layoutDirection=”rtl” را به Layout اصلی اکتیویتی اضافه کردم، با استفاده از متد setLayoutDirection نیز تمامی عناصر موجود در اکتیویتی به حالت راست چین تغییر وضعیت پیدا می‌کنند.<br />
نحوه‌ی راست چین کردن Toolbar در اندروید را بررسی کردیم. پیاده سازی هردو روش به سادگی امکان‌پذیر است و نیازی به اعمال تغییرات در View ها نیست. البته کار همیشه به همین سادگی نخواهد بود. در مواردی ممکن است نیاز به اعمال تغییرات در عناصر موجود در صفحه باشد که در وب مقالات متعددی در این خصوص وجود دارد. یا اگر تمایل دارید اپلیکیشن راست چین شما از دیوایس‌های با API پایینتر از ۱۷ نیز به خوبی پشتیبانی کند، کار مقداری پیچیده‌تر خواهد شد. به امید خدا من هم در ادامه آموزش‌ها به نحوه‌ی راست چین کردن سایر قسمت‌های یک پروژه اندرویدی خواهم پرداخت.</p>
<h3>مطالعه‌ی بیشتر:</h3>
<p style="text-align: left; direction: ltr;">
<a href="https://developer.android.com/reference/android/util/LayoutDirection" target="_blank" rel="noopener noreferrer">https://developer.android.com/reference/android/util/LayoutDirection</a>
</p>
<div class="alert dlbox">
<span class="title"><i class="titleicon fa fa-download fa-lg"></i>دانلود نسخه PDF این آموزش</span><br />
<i class="dlicon fa fa-square fa-lg"></i> تعداد صفحات : ۷<br />
<i class="dlicon fa fa-square fa-lg"></i> حجم : ۱ مگابایت<br />
<i class="dlicon fa fa-square fa-lg"></i> قیمت : رایگان<br />
<a href="http://dl.android-studio.ir/courses/9_3_2_rtl_toolbar.zip" class="button green edd-submit">دانلود رایگان با حجم ۱ مگابایت</a> <a href="http://dl2.android-studio.ir/courses/9_3_2_rtl_toolbar.zip" class="button red edd-submit">لینک کمکی</a>
</div>
<p>نوشته <a href="https://android-studio.ir/android-toolbar-rtl-support/">راست چین کردن Toolbar متریال اندروید</a> اولین بار در <a href="https://android-studio.ir">اندروید استودیو</a> پدیدار شد.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://android-studio.ir/android-toolbar-rtl-support/feed/</wfw:commentRss>
			<slash:comments>6</slash:comments>
		
		
			</item>
		<item>
		<title>کار با TextInputLayout و Floating Label متریال دیزاین</title>
		<link>https://android-studio.ir/android-textinputlayout-floating-label/</link>
					<comments>https://android-studio.ir/android-textinputlayout-floating-label/#comments</comments>
		
		<dc:creator><![CDATA[سیدمهدی مطهری]]></dc:creator>
		<pubDate>Fri, 22 Jun 2018 17:39:54 +0000</pubDate>
				<category><![CDATA[آموزش‌های پایه]]></category>
		<category><![CDATA[آموزش‌های رایگان]]></category>
		<category><![CDATA[رابط_کاربری]]></category>
		<category><![CDATA[رابط_کاربری_اندروید]]></category>
		<category><![CDATA[متریال_دیزاین]]></category>
		<guid isPermaLink="false">https://android-studio.ir/?p=107340</guid>

					<description><![CDATA[<p>معرفی TextInputLayout: به‌نام خدا. در این مبحث به قابلیتی با عنوان Floating Label می‌پردازیم که بر روی EditText اجرا می‌شود. در گذشته با Hint آشنا شدیم. با استفاده از این ویژگی می‌توانستیم یک توضیح کوتاه به یک EditText اضافه کنیم که با پر شدن فیلد توسط کاربر، Hint نیز مخفی می‌شد. اما برای زیبایی بیشتر [&#8230;]</p>
<p>نوشته <a href="https://android-studio.ir/android-textinputlayout-floating-label/">کار با TextInputLayout و Floating Label متریال دیزاین</a> اولین بار در <a href="https://android-studio.ir">اندروید استودیو</a> پدیدار شد.</p>
]]></description>
										<content:encoded><![CDATA[<h2>معرفی TextInputLayout:</h2>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/textinputlayout/floating_label.gif" alt="آموزش ساخت Floating Label متریال در اندروید" /></p>
<p>به‌نام خدا. در این مبحث به قابلیتی با عنوان <a href="http://android-studio.ir/android-textinputlayout-floating-label/" target="_blank" rel="noopener noreferrer">Floating Label</a> می‌پردازیم که بر روی EditText اجرا می‌شود. در گذشته با Hint آشنا شدیم. با استفاده از این ویژگی می‌توانستیم یک توضیح کوتاه به یک EditText اضافه کنیم که با پر شدن فیلد توسط کاربر، Hint نیز مخفی می‌شد. اما برای زیبایی بیشتر فیلدهایی که دارای Hint می‌باشند می‌توانیم قابلیتی پیاده سازی کنیم که با لمس EditText توسط کاربر و وارد کردن مقدار، Hint حذف نشده و با یک حالت انیمیشن به بالای فیلد منتقل شود. برای پیاده سازی این قابلیت به کتابخانه Support Design و تگ TextInputLayout نیاز داریم. ضمنا از این کامپوننت برای نمایش Error ها نیز استفاده می‌شود.</p>
<p>یک پروژه جدید با نام <a href="http://android-studio.ir/android-textinputlayout-floating-label/" target="_blank" rel="noopener noreferrer">TextInputLayout</a> و یک Empty Activity ایجاد می‌کنم.<br />
در ابتدا لازم است کتابخانه design را به پروژه اضافه کنم:</p>
<pre class="brush: java; title: ; notranslate">
dependencies {
    implementation fileTree(dir: 'libs', include: &#x5B;'*.jar'])
    implementation 'com.android.support:appcompat-v7:27.1.1'
    implementation 'com.android.support:design:27.1.1'
}
</pre>
<p>قصد دارم دو EditText برای دریافت نام کاربری و رمز عبور کاربر به اکتیویتی اضافه کنم:</p>
<p>activity_main.xml:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;LinearLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    android:orientation=&quot;vertical&quot;
    tools:context=&quot;.MainActivity&quot;&gt;

    &lt;android.support.design.widget.TextInputLayout
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:id=&quot;@+id/user_layout&quot;&gt;

        &lt;EditText
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:id=&quot;@+id/user_edittext&quot;
            android:hint=&quot;Username&quot;/&gt;

    &lt;/android.support.design.widget.TextInputLayout&gt;


    &lt;android.support.design.widget.TextInputLayout
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:id=&quot;@+id/pass_layout&quot;&gt;

        &lt;EditText
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:id=&quot;@+id/pass_edittext&quot;
            android:hint=&quot;Password&quot;
            android:inputType=&quot;textPassword&quot;/&gt;

    &lt;/android.support.design.widget.TextInputLayout&gt;

&lt;/LinearLayout&gt;
</pre>
<p>هر EditText درون یک تگ TextInputLayout قرار می‌گیرد.<br />
پروژه را اجرا می‌کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/textinputlayout/TextInputLayout.png" alt="آموزش کار با TextInputLayout در اندروید" /></p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/textinputlayout/TextInputLayout_2.png" alt="آموزش کار با TextInputLayout در اندروید" /></p>
<p>با اجرای پروژه، اولین EditText یعنی Username در حالت Focus قرار می‌گیرد که آماده وارد کردن کاراکتر است. هر آیتمی که در حالت Focus باشد رنگ Hint و خط زیر آن قرمز و مابقی آیتم‌ها خاکستری است.<br />
ممکن است بخواهیم آیتمی غیر از آیتم اول در حالت Focus باشد. یا بهرحال تعیین کنیم یک آیتم خاص به عنوان آیتم Focus شده نمایش داده شود. به کد زیر دقت کنید:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;android.support.design.widget.TextInputLayout
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:id=&quot;@+id/pass_layout&quot;&gt;

    &lt;EditText
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:id=&quot;@+id/pass_edittext&quot;
        android:hint=&quot;Password&quot;
        android:inputType=&quot;textPassword&quot;/&gt;
    &lt;requestFocus/&gt;

&lt;/android.support.design.widget.TextInputLayout&gt;
</pre>
<p>من یک تگ requestFocus به <a href="http://android-studio.ir/android-textinputlayout-floating-label/" target="_blank" rel="noopener noreferrer">TextInputLayout</a> مربوط به آیتم Password اضافه کردم که در اجرای مجدد پروژه هم این فیلد Focus شده:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/textinputlayout/requestFocus_attribute_for_TextInputLayout.png" alt="تگ requestFocus" /></p>
<p>در حال حاضر همیشه یک EditText باید در حالت Focus باشد. اما بهتر است حالتی را پیاده سازی کنیم که اگر کاربر نقطه ای از صفحه (بجز محل این دو آیتم) را لمس کند، آیتمی که Focus هست از این حالت خارج شده و در نهایت تمامی آیتم ها در حالت عادی نمایش داده شوند.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;LinearLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    android:orientation=&quot;vertical&quot;
    tools:context=&quot;.MainActivity&quot;
    android:focusable=&quot;true&quot;
    android:focusableInTouchMode=&quot;true&quot;
    android:id=&quot;@+id/main_layout&quot;&gt;

    &lt;android.support.design.widget.TextInputLayout
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:id=&quot;@+id/user_layout&quot;&gt;

        &lt;EditText
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:id=&quot;@+id/user_edittext&quot;
            android:hint=&quot;Username&quot;/&gt;

    &lt;/android.support.design.widget.TextInputLayout&gt;


    &lt;android.support.design.widget.TextInputLayout
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:id=&quot;@+id/pass_layout&quot;&gt;

        &lt;EditText
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:id=&quot;@+id/pass_edittext&quot;
            android:hint=&quot;Password&quot;
            android:inputType=&quot;textPassword&quot;/&gt;
        &lt;requestFocus/&gt;

    &lt;/android.support.design.widget.TextInputLayout&gt;

&lt;/LinearLayout&gt;
</pre>
<p>Layout ریشه اکتیویتی یک LinearLayout است. به این لایه دو خاصیت focusable و focusableInTouchMode با مقدار true و یک id اضافه کردم. سپس در Backend اکتیویتی این لایه را تعریف نموده و برای آن یک متد Listener می‌سازم که ورودی آن null است:</p>
<p>MainActivity.java:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.textinputlayout;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.LinearLayout;

public class MainActivity extends AppCompatActivity {

    LinearLayout mLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mLayout = findViewById(R.id.main_layout);
        mLayout.setOnClickListener(null);

    }
}
</pre>
<p>مقدار null برای این setOnClickListener باعث می‌شود تا هنگام کلیک (لمس) صفحه که من از نوع LinearLayout ساخته ام، همه EditText ها در حالت غیر Focus قرار گیرند:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/textinputlayout/unfocus.png" alt="خارج شدن EditText ها از حالت فوکوس" /></p>
<p>ضمنا با اضافه شدن دو خاصیت فوق به لایه اصلی، هیچکدام از آیتم ها در ابتدای اجرای پروژه به صورت پیش فرض Focus نیستند.<br />
قبل از ادامه آموزش، تگ requestFocus را هم غیر فعال (کامنت) می‌کنم زیرا نمی‌خواهم هیچ آیتمی فوکوس باشد.</p>
<h2>مدیریت Error ها در TextInputLayout:</h2>
<p>مطمئنا همه ما هنگام تکمیل فرم ها به ارورهایی برخورد کرده ایم. این فرم می‌تواند یک فرم ثبت نام در یک وب سایت یا یک اپلیکیشن باشد. به عنوان مثال در فیلد مربوط به کد پستی، اخطار &#8220;کد وارد شده باید ده رقم باشد&#8221; به کاربر اعلام می‌شود.<br />
تصمیم دارم برای فیلد Username یک error تعریف کنم. </p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.textinputlayout;

import android.support.design.widget.TextInputLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.LinearLayout;

public class MainActivity extends AppCompatActivity {

    LinearLayout mLayout;
    TextInputLayout userLayout, passLayout;
    EditText userEdittext, passEdittext;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mLayout = findViewById(R.id.main_layout);
        mLayout.setOnClickListener(null);

        userLayout = findViewById(R.id.user_layout);
        passLayout = findViewById(R.id.pass_layout);

        userEdittext = findViewById(R.id.user_edittext);
        passEdittext = findViewById(R.id.pass_edittext);

        userEdittext.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View view, boolean b) {

                if (userEdittext.getText().toString().isEmpty()) {
                    userLayout.setError(&quot;Enter Username!&quot;);
                } else {
                    userLayout.setErrorEnabled(false);
                }

            }
        });

    }

}
</pre>
<p>در کد بالا از متد setOnFocusChangeListener استفاده شده:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/textinputlayout/setOnFocusChangeListener_method.png" alt="متد setOnFocusChangeListener" /></p>
<pre class="brush: java; title: ; notranslate">
userEdittext.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View view, boolean b) {

    }
});
</pre>
<p>این متد هنگامی اجرا می‌شود که کاربر روی یک EditText ضربه بزند و آن فیلد در حالت فوکوس قرار بگیرد. متد را به اینصورت تکمیل می‌کنم:</p>
<pre class="brush: java; title: ; notranslate">
userEdittext.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View view, boolean b) {

        if (userEdittext.getText().toString().isEmpty()) {
            userLayout.setError(&quot;Enter Username!&quot;);
        } else {
            userLayout.setErrorEnabled(false);
        }

    }
});
</pre>
<p>یک شرط تعیین کردم که اگر EditText خالی بود، توسط متد setError یک ارور را روی userLayout نمایش بدهد و زمانی که این شرط نقض شد (یعنی فیلد خالی نباشد) ارور غیر فعال شود.<br />
پروژه را اجرا می‌کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/textinputlayout/show_error_by_setOnFocusChangeListener.png" alt="نمایش ارور در EditText" /></p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/textinputlayout/show_error_by_setOnFocusChangeListener_2.png" alt="نمایش ارور توسط TextInputLayout" /></p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/textinputlayout/show_error_by_setOnFocusChangeListener_3.png" alt="نمایش Error در EditText" /></p>
<p>ملاحظه می‌کنید با لمس EditText مربوط به Username بلافاصله اخطار با رنگ قرمز زیر آن نمایش داده می‌شود. در حال حاضر برنامه یک ایراد دارد. با وجود اینکه من کلمه test را تایپ کرده‌ام هنوز اخطار Enter Username حذف نشده و زمانی حذف خواهد شد که کاربر EditText بعدی یا جای دیگری از صفحه را لمس کند تا این آیتم از Focus خارج شود. در صورتی که به محض ورود اولین کاراکتر این ارور باید حذف شود.<br />
با استفاده از متد addTextChangedListener و TextWatcher می‌توانیم تغییرات متن یک EditText را شنود کنیم.</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/textinputlayout/addTextChangedListener_method.png" alt="متد addTextChangedListener در اندروید" /></p>
<pre class="brush: java; title: ; notranslate">
userEdittext.addTextChangedListener(new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

    }

    @Override
    public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

    }

    @Override
    public void afterTextChanged(Editable editable) {

    }
});
</pre>
<p>TextWatcher سه متد دارد که نقش هرکدام از نامش پیداست. beforeTextChanged قبل از تغییر متن، onTextChanged هنگام تغییر متن و afterTextChanged بعد از تغییر متن صدا زده می‌شوند.<br />
در اینجا من به متد دوم نیاز دارم. همان if ای که قبلا نوشتم را درون این متد تکرار می‌کنم:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.textinputlayout;

import android.support.design.widget.TextInputLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.widget.EditText;
import android.widget.LinearLayout;

public class MainActivity extends AppCompatActivity {

    LinearLayout mLayout;
    TextInputLayout userLayout, passLayout;
    EditText userEdittext, passEdittext;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mLayout = findViewById(R.id.main_layout);
        mLayout.setOnClickListener(null);

        userLayout = findViewById(R.id.user_layout);
        passLayout = findViewById(R.id.pass_layout);

        userEdittext = findViewById(R.id.user_edittext);
        passEdittext = findViewById(R.id.pass_edittext);

        userEdittext.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View view, boolean b) {

                if (userEdittext.getText().toString().isEmpty()) {
                    userLayout.setError(&quot;Enter Username!&quot;);
                } else {
                    userLayout.setErrorEnabled(false);
                }

            }
        });

        userEdittext.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

                if (userEdittext.getText().toString().isEmpty()) {
                    userLayout.setError(&quot;Enter Username!&quot;);
                } else {
                    userLayout.setErrorEnabled(false);
                }

            }

            @Override
            public void afterTextChanged(Editable editable) {

            }
        });

    }

}
</pre>
<p>حالا با وارد کردن اولین کاراکتر، اخطار حذف می‌شود:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/textinputlayout/onTextChanged_method.png" alt="متد onTextChanged در اندروید" /></p>
<p>با استفاده از خاصیت textColorHint می‌توان رنگ Hint یا همان Floating Label را تغییر داد:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;android.support.design.widget.TextInputLayout
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:id=&quot;@+id/user_layout&quot;
    android:textColorHint=&quot;#36cb1f&quot;&gt;

    &lt;EditText
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:id=&quot;@+id/user_edittext&quot;
        android:hint=&quot;Username&quot;/&gt;

&lt;/android.support.design.widget.TextInputLayout&gt;
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/textinputlayout/textColorHint_attribute.png" alt="خاصیت textColorHint در اندروید" /></p>
<p>خاصیت hintTextAppearance هم برای استایل دهی به Hint هنگامی که Focus شده، بکار می‌رود:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;style name=&quot;TextInputStyle&quot; parent=&quot;TextAppearance.AppCompat&quot;&gt;
    &lt;item name=&quot;android:textColor&quot;&gt;#434ab2&lt;/item&gt;
    &lt;item name=&quot;android:textSize&quot;&gt;16dp&lt;/item&gt;
&lt;/style&gt;
</pre>
<pre class="brush: xml; title: ; notranslate">
&lt;android.support.design.widget.TextInputLayout
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:id=&quot;@+id/user_layout&quot;
    android:textColorHint=&quot;#36cb1f&quot;
    app:hintTextAppearance=&quot;@style/TextInputStyle&quot;&gt;

    &lt;EditText
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:id=&quot;@+id/user_edittext&quot;
        android:hint=&quot;Username&quot;/&gt;

&lt;/android.support.design.widget.TextInputLayout&gt;
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/textinputlayout/hintTextAppearance_attribute.png" alt="خاصیت hintTextAppearance در اندروید" /></p>
<p>بهتر است استایلی که تعریف می‌کنیم از TextAppearance.AppCompat ارث بری کند.<br />
متن Error را هم به همین صورت و توسط خاصیت errorTextAppearance می‌توان استایل دهی کرد:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;style name=&quot;ErrorInputStyle&quot; parent=&quot;TextAppearance.AppCompat&quot;&gt;
    &lt;item name=&quot;android:textColor&quot;&gt;#731539&lt;/item&gt;
    &lt;item name=&quot;android:textSize&quot;&gt;16dp&lt;/item&gt;
&lt;/style&gt;
</pre>
<pre class="brush: xml; title: ; notranslate">
&lt;android.support.design.widget.TextInputLayout
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:id=&quot;@+id/user_layout&quot;
    android:textColorHint=&quot;#36cb1f&quot;
    app:hintTextAppearance=&quot;@style/TextInputStyle&quot;
    app:errorTextAppearance=&quot;@style/ErrorInputStyle&quot;&gt;

    &lt;EditText
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:id=&quot;@+id/user_edittext&quot;
        android:hint=&quot;Username&quot;/&gt;

&lt;/android.support.design.widget.TextInputLayout&gt;
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/textinputlayout/errorTextAppearance_attribute.png" alt="خاصیت errorTextAppearance در اندروید" /></p>
<p>در TextInputLayout قابلیت دیگری با نام Counter (شمارنده) تعریف شده. کاربرد شمارنده در مواقعی است که بخواهیم تعداد کاراکترهای مناسب را به کاربر اعلام کنیم:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;android.support.design.widget.TextInputLayout
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:id=&quot;@+id/pass_layout&quot;
    app:counterEnabled=&quot;true&quot;
    app:counterMaxLength=&quot;8&quot;&gt;

    &lt;EditText
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:id=&quot;@+id/pass_edittext&quot;
        android:hint=&quot;Password&quot;
        android:inputType=&quot;textPassword&quot; /&gt;
    &lt;!-- &lt;requestFocus/&gt; --&gt;

&lt;/android.support.design.widget.TextInputLayout&gt;
</pre>
<p>خاصیت counterEnabled برای فعال کردن این ویژگی و counterMaxLength برای تعیین تعداد کاراکتر استفاده شده است:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/textinputlayout/TextInputLayout_counter_attribute.png" alt="قابلیت Counter یا شمارنده در TextInputLayout اندروید" /></p>
<p>با وارد کردن هر کاراکتر درون این EditText یک شماره به عدد سمت چپ اضافه می‌شود.<br />
در صورتی که تعداد کاراکتر ورودی از مقدار MaxLength بیشتر شود، رنگ شمارنده تغییر می‌کند. تعیین رنگ شمارنده در حالت عادی و حالتی که تعداد کاراکترها از مقدار تعیین شده تجاوز کند به ترتیب توسط دو خاصیت counterTextAppearance و counterOverflowTextAppearance صورت می‌پذیرد:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;style name=&quot;CounterStyle&quot; parent=&quot;TextAppearance.AppCompat&quot;&gt;
    &lt;item name=&quot;android:textColor&quot;&gt;#30c7ae&lt;/item&gt;
&lt;/style&gt;

&lt;style name=&quot;OverflowStyle&quot; parent=&quot;TextAppearance.AppCompat&quot;&gt;
    &lt;item name=&quot;android:textColor&quot;&gt;#199b85&lt;/item&gt;
&lt;/style&gt;
</pre>
<pre class="brush: xml; title: ; notranslate">
&lt;android.support.design.widget.TextInputLayout
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:id=&quot;@+id/pass_layout&quot;
    app:counterEnabled=&quot;true&quot;
    app:counterMaxLength=&quot;8&quot;
    app:counterTextAppearance=&quot;@style/CounterStyle&quot;
    app:counterOverflowTextAppearance=&quot;@style/OverflowStyle&quot;&gt;

    &lt;EditText
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:id=&quot;@+id/pass_edittext&quot;
        android:hint=&quot;Password&quot;
        android:inputType=&quot;textPassword&quot; /&gt;
    &lt;!-- &lt;requestFocus/&gt; --&gt;

&lt;/android.support.design.widget.TextInputLayout&gt;
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/textinputlayout/counterTextAppearance_attribute.png" alt="خاصیت counterTextAppearance در اندروید" /></p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/textinputlayout/counterOverflowTextAppearance_attribute.png" alt="خاصیت counterOverflowTextAppearance در اندروید" /></p>
<p>خاصیت passwordToggleEnabled آیکونی به EditText های از نوع password اضافه می‌کند که کاربر با لمس آن، پسوردی که وارد کرده را می‌تواند مشاهده می‌کند:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;android.support.design.widget.TextInputLayout
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:id=&quot;@+id/pass_layout&quot;
    app:counterEnabled=&quot;true&quot;
    app:counterMaxLength=&quot;8&quot;
    app:counterTextAppearance=&quot;@style/CounterStyle&quot;
    app:counterOverflowTextAppearance=&quot;@style/OverflowStyle&quot;
    app:passwordToggleEnabled=&quot;true&quot;&gt;

    &lt;EditText
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:id=&quot;@+id/pass_edittext&quot;
        android:hint=&quot;Password&quot;
        android:inputType=&quot;textPassword&quot; /&gt;
    &lt;!-- &lt;requestFocus/&gt; --&gt;

&lt;/android.support.design.widget.TextInputLayout&gt;
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/textinputlayout/passwordToggleEnabled_attribute.png" alt="خاصیت passwordToggleEnabled در اندروید برای نمایش پسورد" /></p>
<p><span class="notice">توجه :</span> سورس پروژه درون پوشه Exercises قرار داده شده است</p>
<p><span class="notice">منابع تکمیلی:</span></p>
<p style="text-align: left; direction: ltr;">
<a href="https://developer.android.com/reference/android/support/design/widget/TextInputLayout" target="_blank" rel="noopener noreferrer">https://developer.android.com/reference/android/support/design/widget/TextInputLayout</a><br />
<a href="https://developer.android.com/reference/com/google/android/material/textfield/TextInputLayout" target="_blank" rel="noopener noreferrer">https://developer.android.com/reference/com/google/android/material/textfield/TextInputLayout</a><br />
<a href="https://developer.android.com/reference/android/text/TextWatcher" target="_blank" rel="noopener noreferrer">https://developer.android.com/reference/android/text/TextWatcher</a>
</p>
<div class="alert dlbox">
<span class="title"><i class="titleicon fa fa-download fa-lg"></i>دانلود فایل این آموزش با فرمت PDF به همراه سورس پروژه</span><br />
<i class="dlicon fa fa-square fa-lg"></i> تعداد صفحات : ۲۱<br />
<i class="dlicon fa fa-square fa-lg"></i> حجم : ۱/۳ مگابایت<br />
<i class="dlicon fa fa-square fa-lg"></i> قیمت : رایگان<br />
<a href="http://dl.android-studio.ir/courses/9_12_textinputlayout.zip" class="button green edd-submit">دانلود رایگان با حجم ۱/۳ مگابایت</a> <a href="http://dl2.android-studio.ir/courses/9_12_textinputlayout.zip" class="button red edd-submit">لینک کمکی</a>
</div>
<p>نوشته <a href="https://android-studio.ir/android-textinputlayout-floating-label/">کار با TextInputLayout و Floating Label متریال دیزاین</a> اولین بار در <a href="https://android-studio.ir">اندروید استودیو</a> پدیدار شد.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://android-studio.ir/android-textinputlayout-floating-label/feed/</wfw:commentRss>
			<slash:comments>13</slash:comments>
		
		
			</item>
		<item>
		<title>کار با Bottom Navigation متریال دیزاین + سورس پروژه</title>
		<link>https://android-studio.ir/android-bottom-navigation/</link>
					<comments>https://android-studio.ir/android-bottom-navigation/#comments</comments>
		
		<dc:creator><![CDATA[سیدمهدی مطهری]]></dc:creator>
		<pubDate>Mon, 04 Jun 2018 11:35:44 +0000</pubDate>
				<category><![CDATA[آموزش‌های پایه]]></category>
		<category><![CDATA[آموزش‌های رایگان]]></category>
		<category><![CDATA[رابط_کاربری]]></category>
		<category><![CDATA[رابط_کاربری_اندروید]]></category>
		<category><![CDATA[متریال_دیزاین]]></category>
		<guid isPermaLink="false">https://android-studio.ir/?p=103080</guid>

					<description><![CDATA[<p>با توجه به اندازه محدود صفحات نمایش دستگاه‌های هوشمند و بویژه دیوایس‌های اندرویدی، طراحان رابط کاربری برنامه‌های اندرویدی همواره سعی‌شان بر این است تا حداکثر استفاده را از فضایی که در اختیار کاربر قرار دارد برده و گزینه‌ها یا صفحات پرکاربرد اپلیکیشن با سهولت بیشتری در دسترس افراد قرار گیرد. قابلیت Bottom Navigation در اندروید [&#8230;]</p>
<p>نوشته <a href="https://android-studio.ir/android-bottom-navigation/">کار با Bottom Navigation متریال دیزاین + سورس پروژه</a> اولین بار در <a href="https://android-studio.ir">اندروید استودیو</a> پدیدار شد.</p>
]]></description>
										<content:encoded><![CDATA[<p>با توجه به اندازه محدود صفحات نمایش دستگاه‌های هوشمند و بویژه دیوایس‌های اندرویدی، طراحان رابط کاربری برنامه‌های اندرویدی همواره سعی‌شان بر این است تا حداکثر استفاده را از فضایی که در اختیار کاربر قرار دارد برده و گزینه‌ها یا صفحات پرکاربرد اپلیکیشن با سهولت بیشتری در دسترس افراد قرار گیرد. قابلیت Bottom Navigation در اندروید یکی از آیتم‌های پرکاربرد در طراحی رابط کاربری اپ‌های اندرویدی به شمار می‌رود.<br />
در این جلسه از سری مباحث <a href="http://android-studio.ir">آموزش برنامه نویسی اندروید</a> با این قابلیت بیشتر آشنا شده و در قالب یک مثال، نحوه پیاده سازی آن را مرحله به مرحله بیان می‌کنیم.</p>
<h2>معرفی Bottom Navigation</h2>
<p>بنام خدا. Bottom Navigation یکی دیگر از <a href="http://android-studio.ir/android-material-design/" target="_blank" rel="noopener noreferrer">کامپوننت‌های متریالی اندروید</a> است که کاری مشابه <a href="http://android-studio.ir/android-tab-with-tablayout-viewpager/" target="_blank" rel="noopener noreferrer">Tabs</a> انجام می‌دهد. این کامپوننت در پایین صفحه قرار می‌گیرد و برای نمایش ۳ الی ۵ گزینه مناسب است. </p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/bottomnav/bottom_navigation_example.png" alt="ساخت Bottom Navigation در اندروید" /></p>
<p>در استفاده از کامپوننت Bottom Navigation باید یکسری موارد را مدنظر قرار داد. از جمله:<br />
&#8211;	از Bottom Navigation عموما برای نمایش صفحات و قسمت‌های مهم اپلیکیشن استفاده می‌شود. صفحاتی که به لحاظ اهمیت دارای سطح و تراز یکسانی هستند و کاربر بیشترین سروکار را با آنها دارد. اینستاگرام را درنظر بگیرید:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/bottomnav/instagram_navigation_bottom.png" alt="استفاده از Bottom Navigation در اینستاگرام" /></p>
<p>در نوار پایین صفحه ۵ آیتم قرار گرفته که جزء پرکاربردترین صفحات این اپ است و کاربر به راحتی به آنها دسترسی دارد.<br />
&#8211;	برخلاف Tabs در اینجا تعداد آیتم‌ها باید محدود بوده (بین ۳ تا ۵) تا نیاز به اسکرول بین آیتم‌ها نباشد. همچنین استفاده از آن برای کمتر از ۳ آیتم هم پیشنهاد نمی‌شود. بنابراین اگر اپ شما فقط دو صفحه مهم دارد، استفاده از این ویجت راه حل مناسب نیست (بجای آن از Tabs و یا Navigation Drawer استفاده کنید).<br />
&#8211;	در صورت استفاده از text label (متن) به همراه آیکون، تا حد امکان متن کوتاه انتخاب شود تا در یک خط قرار گیرد.<br />
&#8211;	استفاده همزمان از Tabs در بالای صفحه و Bottom Navigation در انتهای صفحه ممکن است باعث سردرگمی کاربر شود بنابراین توصیه نمی‌شود.<br />
&#8211;	اندازه متن و آیکون همه آیتم‌ها یکسان تعیین شود.<br />
&#8211;	از بکار بردن رنگهای متفاوت برای آیکون یا متن آیتم‌ها اجتناب کنید. رابط کاربری هرچقدر یکدست و ساده تر باشد برای کاربر تجربه بهتری به همراه دارد.<br />
در گذشته برای پیاده سازی یک Bottom Navigation می‌بایست از کتابخانه‌های متفرقه موجود در سطح وب استفاده می‌شد. یا اینکه توسعه دهنده شخصا این قابلیت را از پایه بنویسد. اما در نسخه ۲۵ کتابخانه Support Design این کامپوننت نیز به صورت رسمی معرفی و اضافه شد.</p>
<h2>ساخت پروژه Bottom Navigation</h2>
<p>مطابق مبحث <a href="http://android-studio.ir/create-android-project-and-its-structure/">آموزش ساخت پروژه در اندروید استودیو</a> یک پروژه اندرویدی با نام BottomNavigation می‌سازم. اکتیویتی را از نوع Empty Activity و زبان را Java انتخاب کردم.<br />
در اولین قدم کتابخانه Design را به پروژه اضافه می‌کنم:</p>
<pre class="brush: java; title: ; notranslate">
dependencies {
    implementation fileTree(dir: 'libs', include: &#x5B;'*.jar'])
    implementation 'com.android.support:appcompat-v7:27.1.1'
    implementation 'com.android.support:design:27.1.1'
}
</pre>
<p>سپس مطابق کد زیر یک BottomNavigationView به Layout اضافه می‌کنم:</p>
<p><span class="filename">activity_main.xml</span></p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;RelativeLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    tools:context=&quot;.MainActivity&quot;&gt;

    &lt;android.support.design.widget.BottomNavigationView
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:id=&quot;@+id/bottom_nav&quot;
        android:layout_alignParentBottom=&quot;true&quot; /&gt;

&lt;/RelativeLayout&gt;
</pre>
<p>با استفاده از خاصیت layout_alignParentBottom ویجت در انتهای صفحه قرار می‌گیرد.<br />
مانند <a href="http://android-studio.ir/android-navigation-drawer/" target="_blank" rel="noopener noreferrer">Navigation Drawer</a> که در مباحث گذشته آشنا شدیم، در اینجا هم برای نمایش آیتم‌ها از Menu استفاده می‌کنیم. در مسیر res > New > Android Resource File یک فایل با نام دلخواه bottom_navigation.xml و از نوع Menu به پروژه اضافه می‌کنم که در نهایت یک فولدر با نام menu و حاوی این فایل به فولدر res اضافه می‌شود.</p>
<p>سه آیتم به صورت زیر داخل menu تعریف می‌کنم:</p>
<p><span class="filename">bottom_navigation.xml</span></p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;menu xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&gt;

    &lt;item
        android:title=&quot;Home&quot;
        android:id=&quot;@+id/item_1&quot;
        android:icon=&quot;@drawable/home&quot; /&gt;

    &lt;item
        android:title=&quot;Account&quot;
        android:id=&quot;@+id/item_2&quot;
        android:icon=&quot;@drawable/account&quot;/&gt;

    &lt;item
        android:title=&quot;Settings&quot;
        android:id=&quot;@+id/item_3&quot;
        android:icon=&quot;@drawable/settings&quot;/&gt;

&lt;/menu&gt;
</pre>
<p>هر آیتم شامل یک title، id و icon است که از آیکون‌های پیش فرض اندروید استودیو در مسیر res > New > Vector Asset استفاده کرده‌ام.<br />
حالا منو را به BottomNavigationView اضافه می‌کنم:</p>
<pre class="brush: xml; title: ; notranslate">
app:menu=&quot;@menu/bottom_navigation&quot;
</pre>
<p>پروژه را اجرا می‌کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/bottomnav/simple_bottom_navigation.png" alt="کار با BottomNavigationView در اندروید استودیو" /></p>
<p>چند خاصیت هم برای customize کردن <a href="http://android-studio.ir/android-bottom-navigation" target="_blank" rel="noopener noreferrer">Bottom Navigation</a> در اختیار داریم:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;android.support.design.widget.BottomNavigationView
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:id=&quot;@+id/bottom_nav&quot;
    android:layout_alignParentBottom=&quot;true&quot;
    app:menu=&quot;@menu/bottom_navigation&quot;
    android:background=&quot;#ffffff&quot;
    app:itemTextColor=&quot;#FF5722&quot;
    app:itemIconTint=&quot;#FF5722&quot;/&gt;
</pre>
<p>خاصیت background که کاربرد آن واضح است و رنگ پس‌زمینه کامپوننت را مشخص می‌کند. دو مورد بعد یعنی itemTextColor و itemIconTint برای تعیین رنگ متن و آیکون استفاده می‌شوند:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/bottomnav/change_text_and_icon_color.png" alt="استفاده از خاصیت های itemTextColor و itemIconTint در Bottom Navigation" /></p>
<p>با تعیین رنگ پس زمینه، shadow نیز به بالای نوار اضافه می‌شود. علاوه بر موارد فوق، خاصیت itemBackground هم داریم که برای تعیین رنگ پس‌زمینه آیتم‌ها بکار می‌رود. برای فهم بهتر، این خاصیت را به کامپوننت اضافه کرده و در دو حالت قرارگیری دیوایس نمایش می‌دهم:</p>
<pre class="brush: xml; title: ; notranslate">
app:itemBackground=&quot;@color/colorPrimary&quot;
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/bottomnav/itemBackground.png" alt="استفاده از خاصیت itemBackground در Bottom navigation" /></p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/bottomnav/itemBackground_landscape.png" alt="" /></p>
<p>با تعریف itemTextColor و itemIconTint رنگ متن و آیکون هرسه آیتم یکسان است. در صورتی که بخواهیم رنگ آیتم انتخاب شده (checked) از سایر آیتم‌ها مجزا باشد، به صورت زیر عمل می‌کنیم:<br />
ابتدا روی res راست کلیک کرده، در مسیر New > Android Resoure File یک فایل xml از نوع Color به پروژه اضافه می‌کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/bottomnav/define_checked_and_unchecked_item_color.png" alt="استفاده از state_checked برای تعیین رنگ آیتم انتخاب شده و انتخاب نشده" /></p>
<div class="alert alert-warning">
<span class="notice">تذکر:</span> با تایید پنجره فوق، یک فولدر جدید با نام color به پروژه اضافه می‌شود.
</div>
<p>فایل را به اینصورت تکمیل می‌کنم:</p>
<p><span class="filename">nav_color.xml</span></p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;selector xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&gt;
    &lt;item android:state_checked=&quot;true&quot; android:color=&quot;#ce0e0e&quot; /&gt;
    &lt;item android:state_checked=&quot;false&quot; android:color=&quot;#6fc97d&quot;/&gt;
&lt;/selector&gt;
</pre>
<p>در کد فوق دو آیتم با خاصیت state_checked و مقادیر true و false تعریف شده که هرکدام یک رنگ را به خود اختصاص داده.<br />
حالا برای دو خاصیت مربوط به رنگ متن و آیکون، فایل فوق را تعریف می‌کنم:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;android.support.design.widget.BottomNavigationView
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:id=&quot;@+id/bottom_nav&quot;
    android:layout_alignParentBottom=&quot;true&quot;
    app:menu=&quot;@menu/bottom_navigation&quot;
    android:background=&quot;#ffffff&quot;
    app:itemTextColor=&quot;@color/nav_color&quot;
    app:itemIconTint=&quot;@color/nav_color&quot; /&gt;
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/bottomnav/checked_and_unchecked_item_color.png" alt="استفاده از state_checked برای تعیین رنگ آیتم انتخاب شده و انتخاب نشده" /></p>
<p>ملاحظه می‌کنید آیتمی که در حالت انتخاب شده قرار دارد رنگ مربوط به مقدار true</p>
<pre class="brush: xml; title: ; notranslate">
&lt;item android:state_checked=&quot;true&quot; android:color=&quot;#ce0e0e&quot; /&gt;
</pre>
<p>و سایر آیتم‌ها رنگ خط زیر (یعنی مقدار false) را نشان می‌دهند:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;item android:state_checked=&quot;false&quot; android:color=&quot;#6fc97d&quot;/&gt;
</pre>
<p>آیتم انتخاب شده، رنگ پیش فرض خود را از colorPrimary تم متریال می‌گیرد بنابراین اگر فقط قصد تغییر رنگ آن را داشته باشیم، کافیست به جای مراحل قبل، یک style جدید تعریف کرده، مقدار colorPrimary را جایگزین کنیم:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;style name=&quot;BottomNavTheme&quot;&gt;
    &lt;item name=&quot;colorPrimary&quot;&gt;#FF5722&lt;/item&gt;
&lt;/style&gt;
</pre>
<pre class="brush: xml; title: ; notranslate">
&lt;android.support.design.widget.BottomNavigationView
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:id=&quot;@+id/bottom_nav&quot;
    android:layout_alignParentBottom=&quot;true&quot;
    app:menu=&quot;@menu/bottom_navigation&quot;
    android:background=&quot;#ffffff&quot;
    android:theme=&quot;@style/BottomNavTheme&quot; /&gt;
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/bottomnav/item_colorPrimary.png" alt="تغییر مقدار colorPrimary برای Bottom Navigation در اندروید استودیو" /></p>
<p>مرحله نهایی، هندل کردن آیتم‌هاست که با انتخاب هر آیتم چه عملی انجام شود. من یک مثال ساده پیاده سازی می‌کنم که با انتخاب هر آیتم، یک text متناسب با آن در وسط صفحه نمایش داده شود.</p>
<p>یک TextView به لایه اضافه می‌کنم:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;RelativeLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
    tools:context=&quot;.MainActivity&quot;&gt;

    &lt;TextView
        android:id=&quot;@+id/text&quot;
        android:layout_width=&quot;wrap_content&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:layout_centerHorizontal=&quot;true&quot;
        android:layout_centerVertical=&quot;true&quot;
        android:text=&quot;TextView&quot; /&gt;
    
    &lt;android.support.design.widget.BottomNavigationView
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:id=&quot;@+id/bottom_nav&quot;
        android:layout_alignParentBottom=&quot;true&quot;
        app:menu=&quot;@menu/bottom_navigation&quot;
        android:background=&quot;#ffffff&quot;
        app:itemTextColor=&quot;@color/nav_color&quot;
        app:itemIconTint=&quot;@color/nav_color&quot; /&gt;

&lt;/RelativeLayout&gt;
</pre>
<p>در ادامه دو ویجت Bottom Navigation و TextView را داخل اکتیویتی تعریف کرده و سپس متد Listener آنرا می‌نویسم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/bottomnav/setOnNavigationItemSelectedListener_method.png" alt="متد setOnNavigationItemSelectedListener اندروید" /></p>
<p><span class="filename">MainActivity.java</span></p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.bottomnavigation;

import android.support.annotation.NonNull;
import android.support.design.widget.BottomNavigationView;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MenuItem;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    BottomNavigationView bottomNav;
    TextView itemText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        bottomNav = findViewById(R.id.bottom_nav);
        itemText = findViewById(R.id.text);

        bottomNav.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                return false;
            }
        });

    }
}
</pre>
<p>از متد setOnNavigationItemSelectedListener برای تعیین عملکرد آیتم‌ها استفاده می‌شود.<br />
متد را با استفاده از یک switch case تکمیل می‌کنم:</p>
<pre class="brush: java; title: ; notranslate">
bottomNav.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {

        switch (item.getItemId()) {

            case R.id.item_1:
                itemText.setText(&quot;Home Item&quot;);
                return true;

            case R.id.item_2:
                itemText.setText(&quot;Account Item&quot;);
                return true;

            case R.id.item_3:
                itemText.setText(&quot;Settings Item&quot;);
                return true;

        }

        return false;
    }
});
</pre>
<p>در switch فوق، تعیین شده تا با دریافت id مربوط به هرکدام از آیتم‌ها، چه متنی در TextView نمایش داده شود.</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/bottomnav/bottom_navigation.gif" alt="ساخت Bottom Navigation در اندروید" /></p>
<p>یک آیتم دیگر به Menu اضافه می‌کنم:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;menu xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&gt;

    &lt;item
        android:title=&quot;Home&quot;
        android:id=&quot;@+id/item_1&quot;
        android:icon=&quot;@drawable/home&quot; /&gt;

    &lt;item
        android:title=&quot;Account&quot;
        android:id=&quot;@+id/item_2&quot;
        android:icon=&quot;@drawable/account&quot;/&gt;

    &lt;item
        android:title=&quot;Settings&quot;
        android:id=&quot;@+id/item_3&quot;
        android:icon=&quot;@drawable/settings&quot;/&gt;

    &lt;item
        android:title=&quot;Premium&quot;
        android:id=&quot;@+id/item_4&quot;
        android:icon=&quot;@drawable/shop&quot;/&gt;

&lt;/menu&gt;
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/bottomnav/show_more_than_3_items.png" alt="نمایش بیش از سه آیتم در Bottom Navigation اندروید" /></p>
<p>ملاحظه می‌کنید در صورتی که آیتم‌ها بیش از سه مورد باشد، فقط لیبل آیتم انتخاب شده نمایش داده می‌شود و مابقی فقط آیکون. در اکثر موارد توسعه دهنده تمایل دارد لیبل تمام آیتم‌ها نمایش داده شود نه فقط آیتم انتخاب شده.<br />
برای یافتن راه حل، عبارت زیر را جستجو کردم:</p>
<p style="text-align: left; direction: ltr;">
How to show more than 3 items in bottomNavigationView
</p>
<p>با مطالعه پرسش و پاسخ‌های موجود در <a href="https://stackoverflow.com/a/44178223" target="_blank" rel="noopener noreferrer">StackOverflow.com</a> متوجه شدم باید قابلیت shiftMode را غیر فعال کنم که کد آن به صورت زیر است:</p>
<pre class="brush: java; title: ; notranslate">
private void disableShiftMode(BottomNavigationView view) {
    BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
    try {
        Field shiftingMode = menuView.getClass().getDeclaredField(&quot;mShiftingMode&quot;);
        shiftingMode.setAccessible(true);
        shiftingMode.setBoolean(menuView, false);
        shiftingMode.setAccessible(false);
        for (int i = 0; i &lt; menuView.getChildCount(); i++) {
            BottomNavigationItemView item = (BottomNavigationItemView) menuView.getChildAt(i);
            item.setShiftingMode(false);
            // set once again checked value, so view will be updated
            item.setChecked(item.getItemData().isChecked());
        }
    } catch (NoSuchFieldException e) {
        Log.e(&quot;BNVHelper&quot;, &quot;Unable to get shift mode field&quot;, e);
    } catch (IllegalAccessException e) {
        Log.e(&quot;BNVHelper&quot;, &quot;Unable to change value of shift mode&quot;, e);
    }
}
</pre>
<p>نیازی نیست وارد جزئیات متد بالا شوید. من هم درک کاملی از عملکرد کد ندارم و صرفا از آن استفاده می‌کنم.<br />
متد را به اکتیویتی اضافه کرده سپس در متد onCreate آنرا فراخوانی می‌کنم:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.bottomnavigation;

import android.support.annotation.NonNull;
import android.support.design.internal.BottomNavigationItemView;
import android.support.design.internal.BottomNavigationMenuView;
import android.support.design.widget.BottomNavigationView;
import android.support.v7.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.view.MenuItem;
import android.widget.TextView;

import java.lang.reflect.Field;

public class MainActivity extends AppCompatActivity {

    BottomNavigationView bottomNav;
    TextView itemText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        bottomNav = findViewById(R.id.bottom_nav);
        itemText = findViewById(R.id.text);

        disableShiftMode(bottomNav);

        bottomNav.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) {

                switch (item.getItemId()) {

                    case R.id.item_1:
                        itemText.setText(&quot;Home Item&quot;);
                        return true;

                    case R.id.item_2:
                        itemText.setText(&quot;Account Item&quot;);
                        return true;

                    case R.id.item_3:
                        itemText.setText(&quot;Settings Item&quot;);
                        return true;

                    case R.id.item_4:
                        itemText.setText(&quot;Premium Item&quot;);
                        return true;

                }

                return false;
            }
        });

    }

    // Method for disabling ShiftMode of BottomNavigationView
    private void disableShiftMode(BottomNavigationView view) {
        BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
        try {
            Field shiftingMode = menuView.getClass().getDeclaredField(&quot;mShiftingMode&quot;);
            shiftingMode.setAccessible(true);
            shiftingMode.setBoolean(menuView, false);
            shiftingMode.setAccessible(false);
            for (int i = 0; i &lt; menuView.getChildCount(); i++) {
                BottomNavigationItemView item = (BottomNavigationItemView) menuView.getChildAt(i);
                item.setShiftingMode(false);
                // set once again checked value, so view will be updated
                item.setChecked(item.getItemData().isChecked());
            }
        } catch (NoSuchFieldException e) {
            Log.e(&quot;BNVHelper&quot;, &quot;Unable to get shift mode field&quot;, e);
        } catch (IllegalAccessException e) {
            Log.e(&quot;BNVHelper&quot;, &quot;Unable to change value of shift mode&quot;, e);
        }
    }

}
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/bottomnav/show_more_than_3_items_2.png" alt="نمایش بیش از 3 گزینه در Bottom Navigation اندروید" /></p>
<p>تقریبا در تمام مواردی مانند مسئله فوق که به یک راه حل نیاز داریم، با یک جستجوی ساده می‌توان به راه حل رسید و لازم نیست خودمان اقدام به پرسش کنیم و چند ساعت و چند روز منتظر پاسخ باشیم. مشکل و سوال ما قبلا سوالی افراد دیگری نیز بوده.</p>
<p class="source">توجه : سورس پروژه‌ها درون پوشه Exercises قرار دارد</p>
<p><span class="notice">منابع تکمیلی:</span></p>
<p style="text-align: left; direction: ltr;">
<a href="https://material.io/design/components/bottom-navigation.html" target="_blank" rel="noopener noreferrer">https://material.io/design/components/bottom-navigation.html</a><br />
<a href="https://developer.android.com/reference/android/support/design/widget/BottomNavigationView" target="_blank" rel="noopener noreferrer">https://developer.android.com/reference/android/support/design/widget/BottomNavigationView</a>
</p>
<div class="alert dlbox">
<span class="title"><i class="titleicon fa fa-download fa-lg"></i>دانلود فایل این آموزش با فرمت PDF به همراه سورس پروژه</span><br />
<i class="dlicon fa fa-square fa-lg"></i> تعداد صفحات : ۱۹<br />
<i class="dlicon fa fa-square fa-lg"></i> حجم : ۱/۲ مگابایت<br />
<i class="dlicon fa fa-square fa-lg"></i> قیمت : رایگان<br />
<a href="http://dl.android-studio.ir/courses/9_11_bottom_navigation.zip" class="button green edd-submit">دانلود رایگان با حجم ۱/۲ مگابایت</a> <a href="http://dl2.android-studio.ir/courses/9_11_bottom_navigation.zip" class="button red edd-submit">لینک کمکی</a>
</div>
<p>نوشته <a href="https://android-studio.ir/android-bottom-navigation/">کار با Bottom Navigation متریال دیزاین + سورس پروژه</a> اولین بار در <a href="https://android-studio.ir">اندروید استودیو</a> پدیدار شد.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://android-studio.ir/android-bottom-navigation/feed/</wfw:commentRss>
			<slash:comments>48</slash:comments>
		
		
			</item>
		<item>
		<title>کار با Bottom Sheet متریال دیزاین</title>
		<link>https://android-studio.ir/android-bottom-sheet/</link>
					<comments>https://android-studio.ir/android-bottom-sheet/#comments</comments>
		
		<dc:creator><![CDATA[سیدمهدی مطهری]]></dc:creator>
		<pubDate>Sun, 27 May 2018 13:34:22 +0000</pubDate>
				<category><![CDATA[آموزش‌های پایه]]></category>
		<category><![CDATA[آموزش‌های رایگان]]></category>
		<category><![CDATA[رابط_کاربری]]></category>
		<category><![CDATA[رابط_کاربری_اندروید]]></category>
		<category><![CDATA[متریال_دیزاین]]></category>
		<guid isPermaLink="false">https://android-studio.ir/?p=101380</guid>

					<description><![CDATA[<p>معرفی Bottom Sheet: به نام خدا. Bottom Sheet یکی دیگر از کامپوننت‌های متریال دیزاین در اندروید است که برای نمایش اطلاعات، منو ها و یا هر چیز دیگری بکار می‌رود. به تعریف ساده، یک صفحه یا نواری است که از پایین صفحه نمایش به سمت بالا باز می‌شود. به طور کلی Bottom Sheet ها را [&#8230;]</p>
<p>نوشته <a href="https://android-studio.ir/android-bottom-sheet/">کار با Bottom Sheet متریال دیزاین</a> اولین بار در <a href="https://android-studio.ir">اندروید استودیو</a> پدیدار شد.</p>
]]></description>
										<content:encoded><![CDATA[<h2>معرفی Bottom Sheet:</h2>
<p>به نام خدا. Bottom Sheet یکی دیگر از کامپوننت‌های <a href="http://android-studio.ir/android-material-design/" target="_blank" rel="noopener noreferrer">متریال دیزاین</a> در اندروید است که برای نمایش اطلاعات، منو ها و یا هر چیز دیگری بکار می‌رود. به تعریف ساده، یک صفحه یا نواری است که از پایین صفحه نمایش به سمت بالا باز می‌شود. به طور کلی Bottom Sheet ها را می‌توان به دو دسته Persistent Bottom Sheet و Modal Bottom Sheet تقسیم کرد.<br />
در ادامه دو مثال از کاربرد این کامپوننت را نشان می‌دهم که تصویر اول مربوط به Google Maps و تصویر دوم Google Drive است:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/bottom/android_bottom_sheet_example_1.jpg" alt="Android Bottom Sheet" /></p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/bottom/android_bottom_sheet_example_2.png" alt="Bottom Sheet در اندروید" /></p>
<p>در Google Maps با Pin کردن یک نقطه روی نقشه، یک Bottom Sheet از پایین صفحه باز می‌شود که حاوی اطلاعات مختصری از مکان انتخاب شده است. سپس با لمس دکمه MORE INFO یا کشیدن نوار به سمت بالا، اطلاعات بیشتری به کاربر ارائه می‌شود که در گوگل مپ، در این حالت تمام صفحه را دربر می‌گیرد.<br />
در گوگل درایو هم از این کامپوننت برای نمایش گزینه‌های مرتبط با فایل و همچنین سایر موارد مانند ساخت فولدر جدید یا آپلود فایل استفاده شده است.<br />
من این مبحث را در قالب چند پروژه تهیه می‌کنم تا درک جزئیات و تفاوت‌ها ساده تر شود.<br />
ابتدا یک <a href="http://android-studio.ir/create-android-project-and-its-structure/" target="_blank" rel="noopener noreferrer">پروژه جدید</a> با نام SimpleBottomSheet و یک Empty Activity ایجاد می‌کنم. برای پیاده سازی Bottom Sheet لازم است کتابخانه Support Design را به پروژه اضافه کنیم:</p>
<pre class="brush: java; title: ; notranslate">
dependencies {
    implementation fileTree(dir: 'libs', include: &#x5B;'*.jar'])
    implementation 'com.android.support:appcompat-v7:27.1.1'
    implementation 'com.android.support:design:27.1.1'
}
</pre>
<p>در این پروژه همانطور که از نام آن پیداست قصد دارم یک Bottom Sheet را در ساده ترین حالت آن معرفی کنم. بنابراین در این مثال فقط با layout اکتیویتی سروکار دارم و از <a href="http://android-studio.ir/آموزش-زبان-جاوا/" target="_blank" rel="noopener noreferrer">Java</a> استفاده نخواهم کرد.<br />
در قدم اول جهت نمایش Bottom Sheet در یک اکتیویتی، باید Root Layout را از نوع CoordinatorLayout انتخاب کنیم:</p>
<p>activity_main.xml:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;android.support.design.widget.CoordinatorLayout 
    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    tools:context=&quot;.MainActivity&quot;&gt;


&lt;/android.support.design.widget.CoordinatorLayout&gt;
</pre>
<p>همانطور که در کد بالا ملاحظه می‌کنید، CoordinatorLayout هم از زیرمجموعه های کتابخانه Design است. از CoordinatorLayout برای کنترل حرکت‌ها در متریال استفاده می‌شود. مانند اجرای animation در حرکت عناصر و المان‌های رابط کاربری. یعنی در Bottom Sheet استفاده از این layout باعث می‌شود تا باز و بسته شدن آن با یک حالت انیمیشن همراه باشد که نسبت به یک باز و بسته شدن عادی و ناگهانی، حس و تجربه بهتری را به کاربر منتقل می‌کند. CoordinatorLayout کاربردهای گسترده ای دارد که در مباحث آتی و در جای مناسب اشاره خواهد شد. به عنوان مثال در برخی از اپ ها با اسکرول به پایین، Toolbar حذف و با اسکرول به بالا، مجدد ظاهر می‌شود که پیاده سازی این عمل با CoordinatorLayout انجام می‌پذیرد.</p>
<p>ابتدا یک Bottom Sheet ساده تعریف کرده و در ادامه توضیحات لازم را قید می‌کنم:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;android.support.design.widget.CoordinatorLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
    tools:context=&quot;.MainActivity&quot;&gt;

    &lt;LinearLayout
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;200dp&quot;
        android:orientation=&quot;vertical&quot;
        android:background=&quot;#009688&quot;
        android:padding=&quot;8dp&quot;
        app:layout_behavior=&quot;android.support.design.widget.BottomSheetBehavior&quot;&gt;

        &lt;TextView
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:textColor=&quot;#fff&quot;
            android:textSize=&quot;20sp&quot;
            android:textStyle=&quot;bold&quot;
            android:text=&quot;Bottom Sheet Title&quot; /&gt;

        &lt;TextView
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:textColor=&quot;#fff&quot;
            android:textSize=&quot;16sp&quot;
            android:text=&quot;Lorem ipsum dolor sit amet, te sed vide delicata,
            per ex salutandi intellegat temporibus, ei insolens molestiae vis.
            Eum ei possim aperiam, fuisset suscipit vim ut. Voluptua repudiare
            gubergren id eum, nullam labores an nam. Sed et tota quaerendum,
            enim elit democritum quo et.
            Lorem ipsum dolor sit amet, te sed vide delicata,
            per ex salutandi intellegat temporibus, ei insolens molestiae vis.
            Eum ei possim aperiam, fuisset suscipit vim ut. Voluptua repudiare
            gubergren id eum, nullam labores an nam. Sed et tota quaerendum,
            enim elit democritum quo et.&quot; /&gt;

    &lt;/LinearLayout&gt;

&lt;/android.support.design.widget.CoordinatorLayout&gt;
</pre>
<p>یک LinearLayout به layout اضافه کردم که حاوی دو TextView می‌باشد. در انتخاب نوع این Layout محدودیتی نیست و از سایر موارد مانند RelativeLayout، ConstraintLayout و&#8230; هم می‌توان استفاده کرد. کاری که باید انجام دهیم، تعیین این LinearLayout به عنوان یک Bottom Sheet است که به اینصورت انجام شده:</p>
<pre class="brush: xml; title: ; notranslate">
app:layout_behavior=&quot;android.support.design.widget.BottomSheetBehavior&quot;
</pre>
<p>با افزودن ویژگی فوق به یک layout، اندروید آنرا به عنوان یک Bottom Sheet درنظر می‌گیرد. مقدار این ویژگی را به صورت دیگری هم می‌توانیم تعریف کنیم:</p>
<pre class="brush: xml; title: ; notranslate">
app:layout_behavior=&quot;@string/bottom_sheet_behavior&quot;
</pre>
<p>کلید Ctrl را نگه داشته، روی مقدار فوق کلیک کنید. به فایل values.xml مربوط به کتابخانه design منتقل می‌شوید که در cache سیستم شما ذخیره شده است. به عنوان فوق برنامه، مسیر محل قرارگیری این فایل که در نوار آدرس اندروید استودیو نمایش داده می‌شود را در درایو مربوطه باز کنید. فولدرهای قبل آن را هم بررسی کنید. تمامی کتابخانه هایی که قبلا یکبار استفاده کردید در اینجا ذخیره شده و برای پروژه های بعدی استفاده می‌شود.<br />
پروژه را اجرا می‌کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/bottom/bottom_sheet_preview.png" alt="Bottom Sheet" /></p>
<p>یک نوار با رنگ پس زمینه و ارتفاع ۲۰۰dp که قبلا تعیین کردم در پایین صفحه ظاهر شده که محتوای آن شامل دو  TextViewمی‌باشد. در حال حاضر این یک نوار ثابت است که با کشیدن به سمت پایین هیچ واکنشی صورت نمی‌پذیرد. خاصیت زیر را با یک مقدار دلخواه به Bottom Sheet (یعنی LinearLayout) اضافه می‌کنم:</p>
<pre class="brush: xml; title: ; notranslate">
app:behavior_peekHeight=&quot;60dp&quot;
</pre>
<p>مجدد پروژه را اجرا می‌کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/bottom/bottom_sheet_peekHeight.gif" alt="behavior_peekHeight" /></p>
<p>با اضافه شدن خاصیت فوق، نوار ابتدا ارتفاعی برابر مقدار تعریف شده یعنی ۶۰dp دارد که با کشیدن نوار به سمت بالا، تا حداکثر ارتفاع خود یعنی ۲۰۰dp باز شده و مجددا با کشیدن آن به سمت پایین، به ارتفاع اولیه یعنی ۶۰dp برمی‌گردد.<br />
واضح است اگر مقدار behavior_peekHeight را برابر با ۰ قرار بدهم، در حالت پیش فرض نوار کاملا مخفی است که در این پروژه قابل استفاده نیست. زیرا برای بالا آوردن نوار مخفی استفاده از جاوا لازم است که در این پروژه قصد کار با جاوا را نداریم.<br />
در قسمت قبل با کشیدن نوار به سمت پایین، در ارتفاع اولیه یعنی ۶۰dp متوقف می‌شود. اما با استفاده از خاصیت behavior_hideable و مقدار true، نوار به طور کلی به پایین صفحه رفته و محو می‌شود:</p>
<pre class="brush: xml; title: ; notranslate">
app:behavior_hideable=&quot;true&quot;
</pre>
<p>بدیهی است مقدار false برای خاصیت فوق، مانند قسمت قبل عمل کرده و نوار کاملا مخفی نمی‌شود.</p>
<p>سورس کامل activity_main.xml:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;android.support.design.widget.CoordinatorLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
    tools:context=&quot;.MainActivity&quot;&gt;

    &lt;LinearLayout
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;200dp&quot;
        android:orientation=&quot;vertical&quot;
        android:background=&quot;#009688&quot;
        android:padding=&quot;8dp&quot;
        app:behavior_peekHeight=&quot;60dp&quot;
        app:behavior_hideable=&quot;true&quot;
        app:layout_behavior=&quot;@string/bottom_sheet_behavior&quot;&gt;

        &lt;TextView
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:textColor=&quot;#fff&quot;
            android:textSize=&quot;20sp&quot;
            android:textStyle=&quot;bold&quot;
            android:text=&quot;Bottom Sheet Title&quot; /&gt;

        &lt;TextView
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:textColor=&quot;#fff&quot;
            android:textSize=&quot;16sp&quot;
            android:text=&quot;Lorem ipsum dolor sit amet, te sed vide delicata,
            per ex salutandi intellegat temporibus, ei insolens molestiae vis.
            Eum ei possim aperiam, fuisset suscipit vim ut. Voluptua repudiare
            gubergren id eum, nullam labores an nam. Sed et tota quaerendum,
            enim elit democritum quo et.
            Lorem ipsum dolor sit amet, te sed vide delicata,
            per ex salutandi intellegat temporibus, ei insolens molestiae vis.
            Eum ei possim aperiam, fuisset suscipit vim ut. Voluptua repudiare
            gubergren id eum, nullam labores an nam. Sed et tota quaerendum,
            enim elit democritum quo et.&quot; /&gt;

    &lt;/LinearLayout&gt;

&lt;/android.support.design.widget.CoordinatorLayout&gt;
</pre>
<div class="alert alert-warning">
<span class="notice">تذکر:</span> سورس فوق با نام activity_main_linear.xml در کنار سورس اصلی پروژه قرار داده شده است.
</div>
<p>در قسمت قبل، layout نوار Bottom Sheet از نوع LinearLayout بود. من در TextView دوم یک متن نسبتا طولانی استفاده کردم. اما در حال حاضر فقط قسمتی از متن و بطور کل محتوای نوار برای کاربر نمایش داده می‌شود و مابقی آن مخفی است. یعنی فقط به اندازه ۲۰۰dp را نشان می‌دهد و قابلیت اسکرول فعال نیست تا کاربر بتواند ادامه محتوا را نیز مشاهده کند. جهت رفع این مساله لازم است یک NestedScrollView را جایگزین LinearLayout کنیم:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;android.support.design.widget.CoordinatorLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
    tools:context=&quot;.MainActivity&quot;&gt;

    &lt;android.support.v4.widget.NestedScrollView
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;200dp&quot;
        android:background=&quot;#009688&quot;
        android:padding=&quot;8dp&quot;
        app:behavior_peekHeight=&quot;60dp&quot;
        app:behavior_hideable=&quot;true&quot;
        app:layout_behavior=&quot;@string/bottom_sheet_behavior&quot;&gt;

        &lt;LinearLayout
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:orientation=&quot;vertical&quot;&gt;

            &lt;TextView
                android:layout_width=&quot;match_parent&quot;
                android:layout_height=&quot;wrap_content&quot;
                android:textColor=&quot;#fff&quot;
                android:textSize=&quot;20sp&quot;
                android:textStyle=&quot;bold&quot;
                android:text=&quot;Bottom Sheet Title&quot; /&gt;

            &lt;TextView
                android:layout_width=&quot;match_parent&quot;
                android:layout_height=&quot;wrap_content&quot;
                android:textColor=&quot;#fff&quot;
                android:textSize=&quot;16sp&quot;
                android:text=&quot;Lorem ipsum dolor sit amet, te sed vide delicata,
            per ex salutandi intellegat temporibus, ei insolens molestiae vis.
            Eum ei possim aperiam, fuisset suscipit vim ut. Voluptua repudiare
            gubergren id eum, nullam labores an nam. Sed et tota quaerendum,
            enim elit democritum quo et.
            Lorem ipsum dolor sit amet, te sed vide delicata,
            per ex salutandi intellegat temporibus, ei insolens molestiae vis.
            Eum ei possim aperiam, fuisset suscipit vim ut. Voluptua repudiare
            gubergren id eum, nullam labores an nam. Sed et tota quaerendum,
            enim elit democritum quo et.&quot; /&gt;

        &lt;/LinearLayout&gt;

    &lt;/android.support.v4.widget.NestedScrollView&gt;

&lt;/android.support.design.widget.CoordinatorLayout&gt;
</pre>
<p>(دقت کنید داخل NestedScrollView جهت چینش عناصر از یک LinearLayout استفاده شده)<br />
حالا با اجرای مجدد پروژه امکان اسکرول محتوا نیز فراهم شده و بعد از آنکه نوار به سمت بالا کشیده شد و در حداکثر ارتفاع خود یعنی ۲۰۰dp قرار گرفت، با اسکرول مجدد به سمت بالا، ادامه محتوا نمایش داده می‌شود و به همین ترتیب برای اسکرول به سمت پایین.</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/bottom/bottom_sheet_scroll.gif" alt="استفاده از NestedScrollView در Bottom Sheet" /></p>
<div class="alert alert-warning">
<span class="notice">تذکر:</span> پروژه فوق، با نام SimpleBottomSheet در پوشه Exercises قرار دارد.
</div>
<p>در پروژه قبل با کلیّت این کامپوننت متریالی آشنا شدیم. در ادامه قصد دارم دو نوع Persistent و Modal را در دو پروژه جداگانه بررسی کنم. البته شاید نتوان از نظر تفاوت کاربرد این دو، یک مرز مشخص تعیین کرد اما بعد از مطالعه ادامه مبحث، تا حدود زیادی نوع کاربرد هریک از این دو مورد روشن می‌شود.</p>
<h2>Persistent Bottom Sheet:</h2>
<p>از این حالت عموما جهت نمایش محتوا استفاده می‌شود. مواردی مانند &#8220;جزئیات بیشتر&#8221;، &#8220;اطلاعات تکمیلی&#8221; و سایر موارد مشابه که بین محتوای اصلی موجود در صفحه و محتوای Bottom Sheet یک ارتباط وجود دارد و در واقع به نوعی این نوار نقش تکمیل کننده صفحه اصلی را دارد.<br />
مجدد به مثال اولی که در ابتدای مبحث اشاره شد دقت کنید:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/bottom/android_bottom_sheet_example_1.jpg" alt="Persistent Bottom Sheet" /></p>
<p>کاربر با انتخاب یک نقطه بر روی نقشه، ابتدا اطلاعات کلی از جمله نام مکان و مسافت را مشاهده می‌کند که در ادامه با کشیدن نوار به بالا یا انتخاب دکمه MORE INFO، توضیحات تکمیلی را نیز دریافت خواهد کرد. به عبارت دیگر، محتوای این نوار، اطلاعات داخلی برنامه محسوب می‌گردد و ارتباطی با خارج از آن ندارد.<br />
یک پروژه با نام PersistentBottomSheet و یک Empty Activity ایجاد می‌کنم.<br />
مانند پروژه قبل، اینجا هم لازم است کتابخانه design را اضافه کنم.<br />
در این پروژه می‌خواهم با کلیک روی یک دکمه، یک Bottom Sheet باز و بسته شود. بنابراین به دلیل آنچه در پروژه قبل ذکر شد، ابتدا layout ریشه را به CoordinatorLayout تغییر داده، سپس یک Button به آن اضافه می‌کنم:</p>
<p>activity_main.xml:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;android.support.design.widget.CoordinatorLayout
    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    tools:context=&quot;.MainActivity&quot;&gt;
    
    &lt;RelativeLayout
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;&gt;

        &lt;Button
            android:id=&quot;@+id/btn_expand&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:layout_centerInParent=&quot;true&quot;
            android:text=&quot;Expand&quot; /&gt;

    &lt;/RelativeLayout&gt;

&lt;/android.support.design.widget.CoordinatorLayout&gt;
</pre>
<p>CoordinatorLayout امکان مدیریت نحوه چینش عناصر را ندارد بنابراین دکمه را درون یک RelativeLayout قرار دادم. در مرحله بعد یک Bottom Sheet به layout اضافه می‌کنم:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;LinearLayout
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:orientation=&quot;vertical&quot;
        android:id=&quot;@+id/bottom_sheet&quot;
        android:background=&quot;#94aab4&quot;
        android:padding=&quot;8dp&quot;
        app:behavior_hideable=&quot;true&quot;
        app:behavior_peekHeight=&quot;60dp&quot;
        app:layout_behavior=&quot;@string/bottom_sheet_behavior&quot;&gt;

        &lt;TextView
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:textColor=&quot;#000000&quot;
            android:textSize=&quot;20sp&quot;
            android:text=&quot;Location: Iran&quot;
            android:paddingBottom=&quot;10dp&quot;
            android:paddingTop=&quot;10dp&quot; /&gt;

        &lt;TextView
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:textColor=&quot;#452f2f&quot;
            android:textSize=&quot;16sp&quot;
            android:text=&quot;Iran is an Islamic republic on the Persian Gulf with historical
sites dating to the Persian Empire. Extensive marble ruins mark
Persepolis, the empire’s capital founded by Darius I in the 6th
century B.C. The modern capital, Tehran, is home to opulent
Golestan Palace, seat of the Qajar Dynasty (1794–۱۹۲۵), plus
modern landmarks such as the 435m-high Milad Tower.&quot;/&gt;

    &lt;/LinearLayout&gt;
</pre>
<p>در اینجا از NestedScrollView استفاده نکردم. ارتفاع هم wrap_content تعیین کردم بنابراین نوار به اندازه محتوای درون آن باز خواهد شد.<br />
بهتر است برای Bottom Sheet یک layout جداگانه ساخته و آنرا درون layout اکتیویتی اصلی include کنم تا نظم بیشتری به کار داده باشم. یک Layout جدید با نام bottom_sheet.xml ایجاد کرده، کد فوق را درون آن قرار می‌دهم:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;LinearLayout
    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:orientation=&quot;vertical&quot;
    android:id=&quot;@+id/bottom_sheet&quot;
    android:background=&quot;#94aab4&quot;
    android:padding=&quot;8dp&quot;
    app:behavior_hideable=&quot;true&quot;
    app:behavior_peekHeight=&quot;60dp&quot;
    app:layout_behavior=&quot;@string/bottom_sheet_behavior&quot;&gt;

    &lt;TextView
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:textColor=&quot;#000000&quot;
        android:textSize=&quot;20sp&quot;
        android:text=&quot;Location: Iran&quot;
        android:paddingBottom=&quot;10dp&quot;
        android:paddingTop=&quot;10dp&quot; /&gt;

    &lt;TextView
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:textColor=&quot;#452f2f&quot;
        android:textSize=&quot;16sp&quot;
        android:text=&quot;Iran is an Islamic republic on the Persian Gulf with historical
sites dating to the Persian Empire. Extensive marble ruins mark
Persepolis, the empire’s capital founded by Darius I in the 6th
century B.C. The modern capital, Tehran, is home to opulent
Golestan Palace, seat of the Qajar Dynasty (1794–۱۹۲۵), plus
modern landmarks such as the 435m-high Milad Tower.&quot;/&gt;

&lt;/LinearLayout&gt;
</pre>
<p>activity_main.xml:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;android.support.design.widget.CoordinatorLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    tools:context=&quot;.MainActivity&quot;&gt;
    
    &lt;RelativeLayout
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;&gt;

        &lt;Button
            android:id=&quot;@+id/btn_expand&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:layout_centerInParent=&quot;true&quot;
            android:text=&quot;Expand&quot; /&gt;

    &lt;/RelativeLayout&gt;

    &lt;include layout=&quot;@layout/bottom_sheet&quot; /&gt;

&lt;/android.support.design.widget.CoordinatorLayout&gt;
</pre>
<p>در حال حاضر با اجرای پروژه، ۶۰dp از ابتدای نوار نمایش داده می‌شود که با کشیدن به سمت بالا، نوار کامل باز خواهد شد. اما قصد دارم این عمل باز شدن توسط دکمه صورت پذیرد. </p>
<p>اکتیویتی را به اینصورت تکمیل می‌کنم:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.persistentbottomsheet;

import android.support.design.widget.BottomSheetBehavior;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;

public class MainActivity extends AppCompatActivity {

    Button btnSheet;
    LinearLayout sheetLayout;
    BottomSheetBehavior bottomSheet;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnSheet = findViewById(R.id.btn_expand);
        sheetLayout = findViewById(R.id.bottom_sheet);
        bottomSheet = BottomSheetBehavior.from(sheetLayout);

        btnSheet.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                bottomSheet.setState(BottomSheetBehavior.STATE_EXPANDED);

            }
        });

    }
}
</pre>
<p>ابتدا Button و LinearLayout مربوط به BottomSheet را توسط id ای که قبلا به آنها اختصاص دادم تعریف کردم. سپس یک نمونه از متد BottomSheetBehavior با نام دلخواه bottomSheet ساختم که توسط متد .from() لایه مربوطه را به آن معرفی کرده ام. </p>
<div class="alert alert-warning">
<span class="notice">نکته:</span> در تعریف sheetLayout می‌توان از View بجای LinearLayout یا NestedScrollView و&#8230; استفاده کرد. زیرا همه اینها از View ارث بری شده اند:</p>
<pre class="brush: java; title: ; notranslate">
View sheetLayout;
</pre>
</div>
<p>در ادامه برای دکمه یک Listener ایجاد کردم. از متد setState() جهت تعیین حالت Bottom Sheet استفاده می‌شود. من حالت STATE_EXPANDED را انتخاب کردم، یعنی با لمس دکمه، نوار در وضعیت Expanded (باز شده) قرار می‌گیرد.<br />
پروژه را اجرا و تست می‌کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/bottom/persistent_bottom_sheet.png" alt="Persistent Bottom Sheet" /></p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/bottom/persistent_bottom_sheet_expanded.png" alt="Persistent Bottom Sheet" /></p>
<p>عملیات به درستی انجام می‌شود و نوار باز شد. در قدم بعد می‌خواهم با لمس دوباره‌ی دکمه، نوار مجددا بسته شود:</p>
<pre class="brush: java; title: ; notranslate">
btnSheet.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {

        if (bottomSheet.getState() == BottomSheetBehavior.STATE_COLLAPSED) {

            bottomSheet.setState(BottomSheetBehavior.STATE_EXPANDED);

        }
        else if (bottomSheet.getState() == BottomSheetBehavior.STATE_EXPANDED) {

            bottomSheet.setState(BottomSheetBehavior.STATE_COLLAPSED);
            
        }

    }
});
</pre>
<p>با استفاده از if else و متد getState() شرطی تعیین کردم تا اگر نوار در وضعیت Collapsed بود، با لمس دکمه به وضعیت Expanded تغییر کند و بلعکس.<br />
در هریک از دو نقش فوق، دکمه عبارت Expand را نشان می‌دهد که منطقی نیست. هنگامی که نوار در وضعیت Expand قرار دارد، نقش دکمه Collapse کردن آن است بنابراین عنوان دکمه نیز باید تغییر کند که با استفاده از setText() درون شرط این اصلاح را صورت می‌دهم:</p>
<pre class="brush: java; title: ; notranslate">
btnSheet.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {

        if (bottomSheet.getState() == BottomSheetBehavior.STATE_COLLAPSED) {

            bottomSheet.setState(BottomSheetBehavior.STATE_EXPANDED);
            btnSheet.setText(&quot;Collapse&quot;);

        }
        else if (bottomSheet.getState() == BottomSheetBehavior.STATE_EXPANDED) {

            bottomSheet.setState(BottomSheetBehavior.STATE_COLLAPSED);
            btnSheet.setText(&quot;Expand&quot;);

        }

    }
});
</pre>
<p>با اجرای مجدد پروژه، نوار در هر وضعیتی که باشد، دکمه عبارت متضاد آنرا نشان می‌دهد.<br />
هنوز یک ایراد دیگر داریم. در حال حاضر اگر وضعیت نوار را فقط با دکمه تغییر دهید همه چیز به خوبی انجام شده و با تغییر حالت نوار، text دکمه هم تغییر می‌کند. اما در صورتی که کاربر نوار را به صورت عادی به طرف بالا یا پایین بکشد، تغییری در text انجام نمی‌شود که یک خطای منطقی است. یعنی اگر دکمه عبارت Expand را نشان می‌دهد و کاربر نوار را بدون استفاده از دکمه Expand کند (بالا ببرد)، باز هم دکمه کلمه Expand را نشان می‌دهد در صورتی که باید با کلمه Collapse جایگزین شود.<br />
در اینجا متدی داریم با نام setBottomSheetCallback که امکان مدیریت Bottom Sheet را فراهم می‌کند:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/bottom/setBottomSheetCallback.png" alt="متد BottomSheetCallback" /></p>
<pre class="brush: java; title: ; notranslate">
bottomSheet.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
    @Override
    public void onStateChanged(@NonNull View bottomSheet, int newState) {
        
    }

    @Override
    public void onSlide(@NonNull View bottomSheet, float slideOffset) {

    }
});
</pre>
<p>این متد دو تابع onStateChanged و onSlide دارد که برای رفع مشکل ایجاد شده از مورد اول استفاده می‌کنیم:</p>
<pre class="brush: java; title: ; notranslate">
public void onStateChanged(@NonNull View bottomSheet, int newState) {

    if (newState == BottomSheetBehavior.STATE_EXPANDED) {
        btnSheet.setText(&quot;Collapse&quot;);
    } else if (newState == BottomSheetBehavior.STATE_COLLAPSED) {
        btnSheet.setText(&quot;Expand&quot;);
    }

}
</pre>
<p>در اینجا با استفاده از newState() یک شرط تعیین شده. به اینصورت که اگر وضعیت جدید روی Expanded بود، دکمه کلمه Collapse را نشان دهد و بلعکس. حالا با اجرای مجدد پروژه همه چیز به درستی کار می‌کند.</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/bottom/setBottomSheetCallback.gif" alt="setBottomSheetCallback" /></p>
<p>با تعیین این شرط، عملا setText هایی که در Listener دکمه تعریف کرده بودم کارایی ندارد و آنها را حذف می‌کنم (در سورس پروژه comment شده است).</p>
<p>MainActivity.java:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.persistentbottomsheet;

import android.support.annotation.NonNull;
import android.support.design.widget.BottomSheetBehavior;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;

public class MainActivity extends AppCompatActivity {

    Button btnSheet;
    LinearLayout sheetLayout;
    BottomSheetBehavior bottomSheet;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnSheet = findViewById(R.id.btn_expand);
        sheetLayout = findViewById(R.id.bottom_sheet);
        bottomSheet = BottomSheetBehavior.from(sheetLayout);

        btnSheet.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                if (bottomSheet.getState() == BottomSheetBehavior.STATE_COLLAPSED) {

                    bottomSheet.setState(BottomSheetBehavior.STATE_EXPANDED);
                    //btnSheet.setText(&quot;Collapse&quot;);

                }
                else if (bottomSheet.getState() == BottomSheetBehavior.STATE_EXPANDED) {

                    bottomSheet.setState(BottomSheetBehavior.STATE_COLLAPSED);
                    //btnSheet.setText(&quot;Expand&quot;);

                }

            }
        });

        bottomSheet.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
            @Override
            public void onStateChanged(@NonNull View bottomSheet, int newState) {

                if (newState == BottomSheetBehavior.STATE_EXPANDED) {
                    btnSheet.setText(&quot;Collapse&quot;);
                } else if (newState == BottomSheetBehavior.STATE_COLLAPSED) {
                    btnSheet.setText(&quot;Expand&quot;);
                }

            }

            @Override
            public void onSlide(@NonNull View bottomSheet, float slideOffset) {

            }
        });

    }
}
</pre>
<p>دو خاصیت behavior_peekHeight و behavior_hideable را به جای xml می‌توان در جاوا نیز تعریف و کنترل کرد (در سورس کامنت شده):</p>
<pre class="brush: java; title: ; notranslate">
bottomSheet.setPeekHeight(0);
bottomSheet.setHideable(true);
</pre>
<div class="alert alert-warning">
<span class="notice">تذکر:</span> پروژه فوق، با نام PersistentBottomSheet در پوشه Exercises قرار دارد.
</div>
<h2>Modal Bottom Sheet:</h2>
<p>در این نوع، در حقیقت ما یک Dialog (مشابه AlertDialog) را به عنوان یک Bottom Sheet نمایش می‌دهیم. مانند مثال دوم ابتدای مبحث. یعنی Google Drive:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/bottom/android_bottom_sheet_example_2.png" alt="Modal Bottom Sheet" /></p>
<p>از Modal عموما جهت نمایش گزینه هایی مانند Share، Copy، Upload و سایر اکشن های مشابه استفاده می‌شود.<br />
یک پروژه جدید با نام ModalBottomSheet و یک Empty Activity ایجاد می‌کنم.<br />
مشابه موارد قبل ابتدا کتابخانه Support Design را به پروژه اضافه می‌کنم.<br />
activity_main.xml را مشابه پروژه قبل می‌سازم با این تفاوت که layout ای که include شده بود حذف می‌شود:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;android.support.design.widget.CoordinatorLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    tools:context=&quot;.MainActivity&quot;&gt;

    &lt;RelativeLayout
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;&gt;

        &lt;Button
            android:id=&quot;@+id/btn_expand&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:layout_centerInParent=&quot;true&quot;
            android:text=&quot;Expand&quot; /&gt;

    &lt;/RelativeLayout&gt;

&lt;/android.support.design.widget.CoordinatorLayout&gt;
</pre>
<p>برای نمایش Bottom Sheet در قالب یک Dialog، یک <a href="http://android-studio.ir/android-fragments/" target="_blank" rel="noopener noreferrer">فرگمنت</a> می‌سازم. بعد از ساخته شدن فرگمنت، باید ارث بری آن را از Fragment به BottomSheetDialogFragment تغییر دهم:</p>
<p>BottomSheetFragment.java:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.modalbottomsheet;

import android.os.Bundle;
import android.support.design.widget.BottomSheetDialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;


public class BottomSheetFragment extends BottomSheetDialogFragment {


    public BottomSheetFragment() {
        // Required empty public constructor
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_bottom_sheet, container, false);
    }

}
</pre>
<div class="alert alert-warning">
<span class="notice">نکته:</span> اگر بعد از ساخت فرگمنت، ارور مربوط به کتابخانه support-v4 گرفتید، نیاز به تغییر آی پی و نصب آن نیست. این کتابخانه برای ایمپورت شدن android.support.v4.app.Fragment اضافه می‌شود که ما در این پروژه به آن نیازی نداریم و بجای Fragment از BottomSheetDialogFragment استفاده می‌کنیم. بنابراین جهت رفع مشکل کافی است com.android.support:support-v4:xx.x.x را از build.gradle حذف کنید.<br />
حذف import android.support.v4.app.Fragment از کلاس فرگمنت فراموش نشود.
</div>
<p>حالا باید layout این فرگمنت را تکمیل کنم. همان محتوایی که برای bottom_sheet.xml پروژه قبل ساخته بودم را در اینجا استفاده می‌کنم:</p>
<p>fragment_bottom_sheet.xml:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;LinearLayout
    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:orientation=&quot;vertical&quot;
    android:id=&quot;@+id/bottom_sheet&quot;
    android:background=&quot;#94aab4&quot;
    android:padding=&quot;8dp&quot;
    app:behavior_hideable=&quot;true&quot;
    app:behavior_peekHeight=&quot;60dp&quot;
    app:layout_behavior=&quot;@string/bottom_sheet_behavior&quot;&gt;

    &lt;TextView
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:textColor=&quot;#000000&quot;
        android:textSize=&quot;20sp&quot;
        android:text=&quot;Location: Iran&quot;
        android:paddingBottom=&quot;10dp&quot;
        android:paddingTop=&quot;10dp&quot; /&gt;

    &lt;TextView
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:textColor=&quot;#452f2f&quot;
        android:textSize=&quot;16sp&quot;
        android:text=&quot;Iran is an Islamic republic on the Persian Gulf with historical
sites dating to the Persian Empire. Extensive marble ruins mark
Persepolis, the empire’s capital founded by Darius I in the 6th
century B.C. The modern capital, Tehran, is home to opulent
Golestan Palace, seat of the Qajar Dynasty (1794–۱۹۲۵), plus
modern landmarks such as the 435m-high Milad Tower.&quot;/&gt;

&lt;/LinearLayout&gt;
</pre>
<p>در مرحله نهایی، یک متد Listener برای دکمه Expand می‌نویسم و داخل آنرا به صورت زیر تکمیل می‌کنم:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.modalbottomsheet;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    Button btnSheet;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnSheet = findViewById(R.id.btn_expand);

        btnSheet.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                BottomSheetFragment bottomFragment = new BottomSheetFragment();
                bottomFragment.show(getSupportFragmentManager(), bottomFragment.getTag());

            }
        });

    }
}
</pre>
<p>ابتدا از فرگمنت یک نمونه با نام bottomFragment ساخته شده. سپس توسط متد show() نمایش داده می‌شود. این متد دو پارامتر ورودی می‌گیرد که اولی FragmentManager و دومی Tag فرگمنت مربوطه است.<br />
پروژه را اجرا می‌کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/bottom/modal_bottom_sheet.png" alt="Modal Bottom Sheet" /></p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/bottom/modal_bottom_sheet_show.png" alt="Modal Bottom Sheet" /></p>
<p>مانند AlertDialog، این نوار نیز دارای یک elevation (ارتفاع) زیاد است و با دکمه back دیوایس و یا کشیدن نوار به سمت پایین حذف می‌شود.</p>
<div class="alert alert-warning">
<span class="notice">تذکر:</span> پروژه فوق، با نام ModalBottomSheet در پوشه Exercises قرار دارد.
</div>
<p><span class="notice">منابع تکمیلی:</span></p>
<p style="text-align: left; direction: ltr;">
<a href="https://developer.android.com/reference/android/support/design/widget/BottomSheetBehavior" target="_blank" rel="noopener noreferrer">https://developer.android.com/reference/android/support/design/widget/BottomSheetBehavior</a><br />
<a href="https://developer.android.com/reference/android/support/design/widget/BottomSheetDialog" target="_blank" rel="noopener noreferrer">https://developer.android.com/reference/android/support/design/widget/BottomSheetDialog</a><br />
<a href="https://developer.android.com/reference/android/support/design/widget/BottomSheetDialogFragment" target="_blank" rel="noopener noreferrer">https://developer.android.com/reference/android/support/design/widget/BottomSheetDialogFragment</a>
</p>
<div class="alert dlbox">
<span class="title"><i class="titleicon fa fa-download fa-lg"></i>دانلود فایل این آموزش با فرمت PDF به همراه سورس پروژه‌ها</span><br />
<i class="dlicon fa fa-square fa-lg"></i> تعداد صفحات : ۲۵<br />
<i class="dlicon fa fa-square fa-lg"></i> حجم : ۲/۳ مگابایت<br />
<i class="dlicon fa fa-square fa-lg"></i> قیمت : رایگان<br />
<a href="http://dl.android-studio.ir/courses/9_10_bottomsheet.zip" class="button green edd-submit">دانلود رایگان با حجم ۲/۳ مگابایت</a> <a href="http://dl2.android-studio.ir/courses/9_10_bottomsheet.zip" class="button red edd-submit">لینک کمکی</a>
</div>
<p>نوشته <a href="https://android-studio.ir/android-bottom-sheet/">کار با Bottom Sheet متریال دیزاین</a> اولین بار در <a href="https://android-studio.ir">اندروید استودیو</a> پدیدار شد.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://android-studio.ir/android-bottom-sheet/feed/</wfw:commentRss>
			<slash:comments>7</slash:comments>
		
		
			</item>
		<item>
		<title>کار با AlertDialog متریال دیزاین</title>
		<link>https://android-studio.ir/android-alertdialog/</link>
					<comments>https://android-studio.ir/android-alertdialog/#comments</comments>
		
		<dc:creator><![CDATA[سیدمهدی مطهری]]></dc:creator>
		<pubDate>Tue, 08 May 2018 20:08:46 +0000</pubDate>
				<category><![CDATA[آموزش‌های پایه]]></category>
		<category><![CDATA[آموزش‌های رایگان]]></category>
		<category><![CDATA[رابط_کاربری]]></category>
		<category><![CDATA[متریال_دیزاین]]></category>
		<guid isPermaLink="false">https://android-studio.ir/?p=97481</guid>

					<description><![CDATA[<p>معرفی AlertDialog: AlertDialog پنجره کوچکی است که یک پیغام به همراه (حداکثر) سه دکمه به کاربر نمایش می دهد. این قابلیت کاربردهای متعددی دارد از جمله نمایش یک اخطار، درخواست تایید یا عدم تایید یک عملیات از کاربر، نمایش یک لیست و درخواست از کاربر جهت انتخاب یک گزینه و&#8230; . یک پروژه با نام [&#8230;]</p>
<p>نوشته <a href="https://android-studio.ir/android-alertdialog/">کار با AlertDialog متریال دیزاین</a> اولین بار در <a href="https://android-studio.ir">اندروید استودیو</a> پدیدار شد.</p>
]]></description>
										<content:encoded><![CDATA[<h2>معرفی AlertDialog:</h2>
<p>AlertDialog پنجره کوچکی است که یک پیغام به همراه (حداکثر) سه دکمه به کاربر نمایش می دهد. این قابلیت کاربردهای متعددی دارد از جمله نمایش یک اخطار، درخواست تایید یا عدم تایید یک عملیات از کاربر، نمایش یک لیست و درخواست از کاربر جهت انتخاب یک گزینه و&#8230; .</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/alertdialog/AlertDialog_demo.png" alt="آموزش ساخت AlertDialog در برنامه نویسی اندروید" /></p>
<p>یک پروژه با نام AlertDialog و یک Empty Activity می سازم. پروژه باید حاوی کتابخانه appcompat-v7 باشد که به صورت پیش فرض هنگام ساخت پروژه اضافه شده است.<br />
درون اکتیویتی یک نمونه از AlertDialog.Builder با نام دلخواه alertBuilder ایجاد کرده سپس درون متد onCreate بصورت زیر new می کنم. </p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.alertdialog;

import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    AlertDialog.Builder alertBuilder;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        alertBuilder = new AlertDialog.Builder(this);

    }
}
</pre>
<p>AlertDialog.Builder فعلا فقط یک پارامتر ورودی گرفته که همان Context است.<br />
دقت کنید AlertDialog مربوط به کتابخانه support را انتخاب نمائید:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/alertdialog/add_AlertDialog.png" alt="اضافه کردن AlertDialog به اکتیویتی" /></p>
<p>ابتدا یک <a href="http://android-studio.ir/android-alertdialog/" target="_blank" rel="noopener noreferrer">AlertDialog</a> ساده با حداقل متدها ایجاد کرده و در ادامه به ارائه جزئیات می‌پردازم:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.alertdialog;

import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    AlertDialog.Builder alertBuilder;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        alertBuilder = new AlertDialog.Builder(this);

        alertBuilder.setTitle(&quot;Alert!&quot;);
        alertBuilder.setMessage(&quot;Delete this item?&quot;);

        alertBuilder.setPositiveButton(&quot;Yes&quot;, null);

        AlertDialog alert = alertBuilder.create();
        alert.show();

    }
}
</pre>
<p>همانطور که از نام متدهای setTitle و setMessage پیداست، این دو مورد برای تعیین عنوان و متن پیغام استفاده می شوند. در ابتدای مبحث گفتیم در AlertDialog تا ۳ دکمه می توان به دیالوگ اضافه کرد که به واسطه متدهای setPositiveButton، setNegativeButton و setNeutralButton قابل پیاده سازی هستند. در کد بالا فعلا فقط یک متد را بکار بردم. یعنی دیالوگ من باید یک دکمه با عنوان Yes داشته باشد. پارامتر دوم مربوط به Listener دکمه است که فعلا null قرار داده ام.<br />
در انتها جهت ساخت و نمایش AlertDialog دو متد create() و show() را استفاده کردم.<br />
پروژه را اجرا می کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/alertdialog/run_AlertDialog.png" alt="ساخت AlertDialog" /></p>
<p>به همین سادگی توانستم یک پنجره پیغام را نمایش بدهم. از آنجایی که در پارامتر دوم دکمه، مقدار null تعریف شده، با انتخاب آن عملا هیچ اتفاقی رخ نداده و صرفا پنجره بسته می شود.<br />
می خواهم برای دکمه فعلی یک Listener تعریف کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/alertdialog/add_listener_to_AlertDialog_button.png" alt="ساخت Listener برای AlertDialog" /></p>
<p>یک Listener از نوع DialogInterface.OnClickListener() جایگزین null شد:</p>
<pre class="brush: java; title: ; notranslate">
alertBuilder.setPositiveButton(&quot;Yes&quot;, new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {

    }
});
</pre>
<p>حالا مانند آنچه در گذشته آموختیم، هر دستوری درون onClick تعریف کنیم، با لمس دکمه اجرا خواهد شد. یک پیغام از جنس Toast به Listener اضافه کرده، پروژه را مجدد اجرا می کنم:</p>
<pre class="brush: java; title: ; notranslate">
alertBuilder.setPositiveButton(&quot;Yes&quot;, new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {

        Toast.makeText(MainActivity.this, &quot;Yes Button Clicked!&quot;, Toast.LENGTH_SHORT).show();

    }
});
</pre>
<p>با لمس دکمه Yes، پیغام مربوطه اجرا می گردد:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/alertdialog/click_on_alertdialog_positivebutton.png" alt="متد setPositiveButton" /></p>
<p>دو متد مربوط به دو دکمه دیگر را نیز به اکتیویتی اضافه می کنم:</p>
<pre class="brush: java; title: ; notranslate">
alertBuilder.setNegativeButton(&quot;No&quot;, new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {

        Toast.makeText(MainActivity.this, &quot;No Button Clicked!&quot;, Toast.LENGTH_SHORT).show();

    }
});

alertBuilder.setNeutralButton(&quot;Later&quot;, new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {

        Toast.makeText(MainActivity.this, &quot;Neutral Button Clicked!&quot;, Toast.LENGTH_SHORT).show();

    }
});
</pre>
<p>با اجرای پروژه، شاهد نمایش سه دکمه در انتهای پنجره هستیم. دکمه مربوط به NeutralButton در سمت چپ قرار می گیرد. </p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/alertdialog/AlertDialog_three_buttons.png" alt="متدهای setNegativeButton و setNeutralButton" /></p>
<p>با استفاده از متد setIcon می توان یک آیکون نیز به عنوان AlertDialog افزود:</p>
<pre class="brush: java; title: ; notranslate">
alertBuilder.setIcon(R.drawable.logo);
</pre>
<p>در خط بالا آیکون با نام logo.png در دایرکتوری drawable پروژه به عنوان آیکون این دیالوگ تعریف شده. </p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/alertdialog/add_icon_logo_to_AlertDialog_title.png" alt="اضافه کردن آیکون لوگو به AlertDialog" /></p>
<p>در حال حاضر اگر هنگامی که AlertDialog روی صفحه نمایش قرار دارد، کاربر خارج از پنجره دیالوگ را لمس کند، پنجره بسته خواهد شد. برای رفع این ایراد کافیست از متد setCancelable استفاده کرده و مقدار آن را false قرار دهیم:</p>
<pre class="brush: java; title: ; notranslate">
alertBuilder.setCancelable(false);
</pre>
<p>با اضافه شدن این متد، تا زمانی که کاربر یکی از دکمه های تعریف شده را انتخاب نکند، پنجره دیالوگ روی صفحه نمایش باقی می ماند و با کلیک روی اطراف آن یا حتی دکمه Back دیوایس، از بین نمی‌رود.<br />
کد کامل AlertDialog:</p>
<pre class="brush: java; title: ; notranslate">
alertBuilder.setTitle(&quot;Alert!&quot;);
alertBuilder.setMessage(&quot;Delete this item?&quot;);
alertBuilder.setIcon(R.drawable.logo);
alertBuilder.setCancelable(false);

alertBuilder.setPositiveButton(&quot;Yes&quot;, new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {

        Toast.makeText(MainActivity.this, &quot;Yes Button Clicked!&quot;, Toast.LENGTH_SHORT).show();

    }
});

alertBuilder.setNegativeButton(&quot;No&quot;, new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {

        Toast.makeText(MainActivity.this, &quot;No Button Clicked!&quot;, Toast.LENGTH_SHORT).show();

    }
});

alertBuilder.setNeutralButton(&quot;Later&quot;, new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {

        Toast.makeText(MainActivity.this, &quot;Neutral Button Clicked!&quot;, Toast.LENGTH_SHORT).show();

    }
});

AlertDialog alert = alertBuilder.create();
alert.show();
</pre>
<p>در نهایت می توانم کد را بصورت زیر خلاصه کنم که تا حدودی از حجم برنامه کاسته می شود:</p>
<pre class="brush: java; title: ; notranslate">
new AlertDialog.Builder(this)
        .setTitle(&quot;Alert!&quot;)
        .setMessage(&quot;Delete this item?&quot;)
        .setIcon(R.drawable.logo)
        .setCancelable(false)
        .setPositiveButton(&quot;Yes&quot;, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {

                Toast.makeText(MainActivity.this, &quot;Yes Button Clicked!&quot;, Toast.LENGTH_SHORT).show();

            }
        })
        .setNegativeButton(&quot;No&quot;, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {

                Toast.makeText(MainActivity.this, &quot;No Button Clicked!&quot;, Toast.LENGTH_SHORT).show();

            }
        })
        .setNeutralButton(&quot;Later&quot;, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {

                Toast.makeText(MainActivity.this, &quot;Neutral Button Clicked!&quot;, Toast.LENGTH_SHORT).show();

            }
        })

.create()
.show();
</pre>
<div class="alert alert-warning">
<span class="notice">تذکر:</span> کد قبل از اصلاح و بهینه سازی فوق، در فایل جداگانه ای با نام MainActivity_first.java در کنار سورس اصلی قرار گرفته است.
</div>
<p>برای راحتتر کردن فرایند تست دیالوگ، یک Button به اکتیویتی اضافه می کنم. سپس کد مربوط به AlertDialog را داخل یک تابع جداگانه تعریف کرده و آنرا درون متد این دکمه فراخوانی می کنم تا با هربار لمس دکمه، پنجره مجدد نمایش داده شود و نیاز به اجرای مجدد پروژه نباشد:</p>
<p>activity_main.xml:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;RelativeLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    tools:context=&quot;.MainActivity&quot;&gt;

    &lt;Button
        android:id=&quot;@+id/button&quot;
        android:layout_width=&quot;wrap_content&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:layout_centerInParent=&quot;true&quot;
        android:text=&quot;Run AlertDialog&quot; /&gt;

&lt;/RelativeLayout&gt;
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/alertdialog/add_button_to_activity.png" alt="اضافه کردن دکمه به اکتیویتی" /></p>
<p>MainActivity.java:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.alertdialog;

import android.content.DialogInterface;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    //AlertDialog.Builder alertBuilder;
    Button alertButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        alertButton = findViewById(R.id.button);
        alertButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                runAlert();
            }
        });

    }

    private void runAlert() {

        new AlertDialog.Builder(this)
                .setTitle(&quot;Alert!&quot;)
                .setMessage(&quot;Delete this item?&quot;)
                .setIcon(R.drawable.logo)
                .setCancelable(false)
                .setPositiveButton(&quot;Yes&quot;, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {

                        Toast.makeText(MainActivity.this, &quot;Yes Button Clicked!&quot;, Toast.LENGTH_SHORT).show();

                    }
                })
                .setNegativeButton(&quot;No&quot;, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {

                        Toast.makeText(MainActivity.this, &quot;No Button Clicked!&quot;, Toast.LENGTH_SHORT).show();

                    }
                })
                .setNeutralButton(&quot;Later&quot;, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {

                        Toast.makeText(MainActivity.this, &quot;Neutral Button Clicked!&quot;, Toast.LENGTH_SHORT).show();

                    }
                })

        .create()
        .show();

    }

}
</pre>
<div class="alert alert-warning">
<span class="notice">تذکر:</span> تمرین فوق، با نام AlertDialog One در پوشه Exercises قرار دارد.
</div>
<p>در ادامه قصد دارم سایر قابلیت های AlertDialog را معرفی کنم. پروژه جدیدی نمی‌سازم و همان پروژه قبل را ویرایش خواهم کرد.<br />
یکی از کاربردهای AlertDialog نمایش یک لیست از آیتم‌هاست که کاربر باید یک گزینه را انتخاب کند. مانند یک بازی که ابتدا از کاربر می‌خواهد سطح بازی را تعیین کند.<br />
ابتدا داخل بدنه اکتیویتی یک نمونه از String[] می سازم و چند مقدار برای آن تعریف می کنم:</p>
<pre class="brush: java; title: ; notranslate">
String&#x5B;] items = {&quot;Easy&quot;, &quot;Medium&quot;, &quot;Hard&quot;, &quot;Very Hard&quot;};
</pre>
<p>سپس این مقادیر را توسط متد setSingleChoiceItems نمایش می دهم:</p>
<pre class="brush: java; title: ; notranslate">
private void runAlert() {

    new AlertDialog.Builder(this)
            .setTitle(&quot;Select Game level&quot;)
            .setCancelable(false)
            .setSingleChoiceItems(items, 2, null)
            .setPositiveButton(&quot;OK&quot;, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {

                    Toast.makeText(MainActivity.this, &quot;Yes Button Clicked!&quot;, Toast.LENGTH_SHORT).show();

                }
            })

            .create()
            .show();

}
</pre>
<p>این متد سه پارامتر ورودی می‌گیرد. پارامتر اول همان items است، یعنی مقادیر آیتم‌های لیست. در پارامتر دوم می‌توانیم تعیین کنیم در حالت پیش فرض کدام آیتم انتخاب شده باشد. من مقدار ۲ را تعیین کردم یعنی گزینه Hard (شمارش از ۰ آغاز می شود). اگر بخواهیم هیچ گزینه ای در ابتدا انتخاب نشده باشد مقدار ۱- وارد می‌کنیم. پارامتر سوم هم مربوط به Listener است که فعلا null تعریف کردم.<br />
توجه داشته باشید از متدهای setMessage و setSingleChoiceItems نمی‌توان همزمان استفاده کرد.<br />
کد کامل MainActivity.java:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.alertdialog;

import android.content.DialogInterface;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    Button alertButton;
    String&#x5B;] items = {&quot;Easy&quot;, &quot;Medium&quot;, &quot;Hard&quot;, &quot;Very Hard&quot;};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        alertButton = findViewById(R.id.button);
        alertButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                runAlert();
            }
        });

    }

    private void runAlert() {

        new AlertDialog.Builder(this)
                .setTitle(&quot;Select Game level&quot;)
                .setCancelable(false)
                .setSingleChoiceItems(items, 2, null)
                .setPositiveButton(&quot;OK&quot;, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {

                        Toast.makeText(MainActivity.this, &quot;Yes Button Clicked!&quot;, Toast.LENGTH_SHORT).show();

                    }
                })

                .create()
                .show();

    }

}
</pre>
<p>پروژه را اجرا می کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/alertdialog/show_list_inAlertDialog.png" alt="نمایش List در AlertDialog" /></p>
<p>مانند دکمه های AlertDialog، برای متد setSingleChoiceItems هم امکان تعریف Listener وجود دارد.<br />
یک نمونه از String با نام دلخواه درون بدنه اکتیویتی تعریف می کنم:</p>
<pre class="brush: java; title: ; notranslate">
String result;
</pre>
<p>حالا Listener را به اینصورت تکمیل می کنم:</p>
<pre class="brush: java; title: ; notranslate">
.setSingleChoiceItems(items, 2, new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {

        result = items&#x5B;i];
        Toast.makeText(MainActivity.this, result + &quot; selected&quot;, Toast.LENGTH_SHORT).show();

    }
})
</pre>
<p>در کد بالا با انتخاب هر آیتم توسط کاربر، نام آن آیتم در یک Toast چاپ می شود:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/alertdialog/add_listener_to_items.png" alt="تعیین Listener برای آیتم های لیست" /></p>
<p>استایل دهی به اجزای AlertDialog نیز امکان‌پذیر است.<br />
یک استایل جدید با نام دلخواه DialogTheme به styles.xml اضافه کردم که از Theme.AppCompat.Light.Dialog.Alert ارث بری شده:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;style name=&quot;DialogTheme&quot; parent=&quot;Theme.AppCompat.Light.Dialog.Alert&quot;&gt;
    &lt;item name=&quot;colorAccent&quot;&gt;#41bf13&lt;/item&gt;
    &lt;item name=&quot;android:textColorPrimary&quot;&gt;#ac2a2a&lt;/item&gt;
    &lt;item name=&quot;android:background&quot;&gt;#c7cc5f&lt;/item&gt;
&lt;/style&gt;
</pre>
<p>برای اتصال استایل به دیالوگ می‌بایست آنرا به عنوان پارامتر ورودی دوم AlertDialog.Builder تعریف کنیم:</p>
<pre class="brush: java; title: ; notranslate">
new AlertDialog.Builder(this, R.style.DialogTheme)
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/alertdialog/add_style_to_AlertDialog.png" alt="تعریف Style برای AlertDialog" /></p>
<p>ممکن است بخواهید برای پنجره دیالوگ یک نوار حاشیه (border) یا انحنا در چهار گوشه (radius) تعریف کنید. برای اینکار ابتدا یک Resource file درون دایرکتوری drawable ایجاد می کنم:</p>
<p>فایل dialog_background.xml:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;inset xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    android:insetLeft=&quot;16dp&quot;
    android:insetTop=&quot;16dp&quot;
    android:insetRight=&quot;16dp&quot;
    android:insetBottom=&quot;16dp&quot;&gt;

    &lt;shape android:shape=&quot;rectangle&quot;&gt;
        &lt;corners android:radius=&quot;8dp&quot; /&gt;
        &lt;solid android:color=&quot;#97e76a&quot; /&gt;
        &lt;stroke android:width=&quot;5dp&quot; android:color=&quot;#303759&quot; /&gt;
    &lt;/shape&gt;
&lt;/inset&gt;
</pre>
<p>لینک توضیحات مربوط به InsetDrawable در انتهای مبحث قید شده. با اینحال نام آیتم ها و خواص بکار رفته در کد بالا گویای کاربرد آنهاست. insetLeft و سه مورد دیگر جهت تعیین فاصله پنجره دیالوگ از حاشیه صفحه نمایش هستند. سپس یک تگ shape داریم که درون آن به ترتیب مقدار انحنای گوشه ها، رنگ پس زمینه و ضخامت نوار حاشیه و رنگ آن تعریف شده اند.<br />
حالا در استایل DialogTheme خط زیر را جایگزین خاصیت background می‌کنم:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;item name=&quot;android:windowBackground&quot;&gt;@drawable/dialog_background&lt;/item&gt;
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/alertdialog/define_insetDrawable.png" alt="استفاده از insetDrawable در اندروید" /></p>
<p>برای هرکدام از دکمه ها هم می‌توانیم یک رنگ جداگانه تعیین کنیم. مجدد دو دکمه دیگر به دیالوگ اضافه می کنم تا در مجموع سه دکمه در اختیار داشته باشم: </p>
<pre class="brush: java; title: ; notranslate">
private void runAlert() {

    new AlertDialog.Builder(this, R.style.DialogTheme)
            .setTitle(&quot;Select Game level&quot;)
            .setCancelable(false)
            .setSingleChoiceItems(items, 2, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {

                    result = items&#x5B;i];
                    Toast.makeText(MainActivity.this, result + &quot; selected&quot;, Toast.LENGTH_SHORT).show();

                }
            })
            .setPositiveButton(&quot;OK&quot;, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {

                    Toast.makeText(MainActivity.this, &quot;Yes Button Clicked!&quot;, Toast.LENGTH_SHORT).show();

                }
            })
            .setNegativeButton(&quot;Cancel&quot;, null)
            .setNeutralButton(&quot;Later&quot;, null)

            .create()
            .show();

}
</pre>
<p>در قدم بعد یک استایل برای هر دکمه تعریف کرده و سپس در استایل DialogTheme به اینصورت اضافه می کنم: </p>
<pre class="brush: xml; title: ; notranslate">
&lt;style name=&quot;DialogTheme&quot; parent=&quot;Theme.AppCompat.Light.Dialog.Alert&quot;&gt;
    &lt;item name=&quot;colorAccent&quot;&gt;#41bf13&lt;/item&gt;
    &lt;item name=&quot;android:textColorPrimary&quot;&gt;#ac2a2a&lt;/item&gt;
    &lt;item name=&quot;android:windowBackground&quot;&gt;@drawable/dialog_background&lt;/item&gt;
    &lt;item name=&quot;buttonBarNegativeButtonStyle&quot;&gt;@style/NegativeButton&lt;/item&gt;
    &lt;item name=&quot;buttonBarPositiveButtonStyle&quot;&gt;@style/PositiveButton&lt;/item&gt;
    &lt;item name=&quot;buttonBarNeutralButtonStyle&quot;&gt;@style/NeutralButton&lt;/item&gt;
&lt;/style&gt;

&lt;style name=&quot;PositiveButton&quot; parent=&quot;Widget.AppCompat.Button.ButtonBar.AlertDialog&quot;&gt;
    &lt;item name=&quot;android:textColor&quot;&gt;#d6062d&lt;/item&gt;
&lt;/style&gt;

&lt;style name=&quot;NegativeButton&quot; parent=&quot;Widget.AppCompat.Button.ButtonBar.AlertDialog&quot;&gt;
    &lt;item name=&quot;android:textColor&quot;&gt;#131e68&lt;/item&gt;
&lt;/style&gt;

&lt;style name=&quot;NeutralButton&quot; parent=&quot;Widget.AppCompat.Button.ButtonBar.AlertDialog&quot;&gt;
    &lt;item name=&quot;android:textColor&quot;&gt;#1da6ba&lt;/item&gt;
&lt;/style&gt;
</pre>
<p>با اجرای پروژه مشاهده می کنید هرکدام از دکمه ها رنگ مختص خود را نشان می‌دهد:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/alertdialog/AlertDialog_buttons_color.png" alt="تعیین رنگ اختصاصی برای دکمه های AlertDialog" /></p>
<div class="alert alert-warning">
<span class="notice">تذکر:</span> کد اکتیویتی فوق، در فایل جداگانه ای با نام MainActivity_first.java در کنار سورس اصلی قرار گرفته است.
</div>
<p>یک قابلیت دیگر که در این مبحث آشنا می‌شویم، امکان استفاده از Custom Layout در AlertDialog است. فرض کنید می‌خواهید در یک پنجره دیالوگ، دو فیلد Username و Password نشان دهید تا کاربر از این طریق وارد حساب کاربری خود در اپ شود.<br />
ابتدا یک layout به پروژه اضافه می کنم:</p>
<p>custom_dialog.xml:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;RelativeLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;&gt;

    &lt;LinearLayout
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:orientation=&quot;vertical&quot;
        android:padding=&quot;20dp&quot;&gt;

        &lt;EditText
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:ems=&quot;10&quot;
            android:inputType=&quot;textPersonName&quot;
            android:text=&quot;Username&quot; /&gt;

        &lt;EditText
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:ems=&quot;10&quot;
            android:inputType=&quot;textPassword&quot;
            android:text=&quot;Password&quot; /&gt;

    &lt;/LinearLayout&gt;

&lt;/RelativeLayout&gt;
</pre>
<p>سپس با استفاده از LayoutInflater، لایه فوق را inflate کرده و در نهایت توسط متد setView() به AlertDialog اضافه می کنم:</p>
<pre class="brush: java; title: ; notranslate">
private void runAlert() {

    LayoutInflater aInflater = getLayoutInflater();
    View alertLayout = aInflater.inflate(R.layout.custom_dialog, null);

    new AlertDialog.Builder(this, R.style.DialogTheme)
            .setTitle(&quot;Login&quot;)
            .setCancelable(false)
            .setView(alertLayout)
            .setPositiveButton(&quot;OK&quot;, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {

                    Toast.makeText(MainActivity.this, &quot;Yes Button Clicked!&quot;, Toast.LENGTH_SHORT).show();

                }
            })

            .create()
            .show();

}
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/alertdialog/view_custom_layout_in_AlertDialog.png" alt="نمایش Custom Layout در AlertDialog" /></p>
<div class="alert alert-warning">
<span class="notice">تذکر:</span> تمرین فوق، با نام AlertDialog Two در پوشه Exercises قرار دارد.
</div>
<p><span class="notice">منابع تکمیلی:</span></p>
<p style="text-align: left; direction: ltr;">
<a href="https://developer.android.com/reference/android/app/AlertDialog" target="_blank" rel="noopener noreferrer">https://developer.android.com/reference/android/app/AlertDialog</a><br />
<a href="https://developer.android.com/reference/android/graphics/drawable/InsetDrawable" target="_blank" rel="noopener noreferrer">https://developer.android.com/reference/android/graphics/drawable/InsetDrawable</a><br />
<a href="https://material.io/guidelines/components/dialogs.html" target="_blank" rel="noopener noreferrer">https://material.io/guidelines/components/dialogs.html</a>
</p>
<div class="alert dlbox">
<span class="title"><i class="titleicon fa fa-download fa-lg"></i>دانلود فایل این آموزش با فرمت PDF به همراه سورس پروژه</span><br />
<i class="dlicon fa fa-square fa-lg"></i> تعداد صفحات : ۲۳<br />
<i class="dlicon fa fa-square fa-lg"></i> حجم : ۱٫۵ مگابایت<br />
<i class="dlicon fa fa-square fa-lg"></i> قیمت : رایگان<br />
<a href="http://dl.android-studio.ir/courses/9_9_alertdialog.zip" class="button green edd-submit">دانلود رایگان با حجم ۱٫۵ مگابایت</a> <a href="http://dl2.android-studio.ir/courses/9_9_alertdialog.zip" class="button red edd-submit">لینک کمکی</a>
</div>
<p>نوشته <a href="https://android-studio.ir/android-alertdialog/">کار با AlertDialog متریال دیزاین</a> اولین بار در <a href="https://android-studio.ir">اندروید استودیو</a> پدیدار شد.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://android-studio.ir/android-alertdialog/feed/</wfw:commentRss>
			<slash:comments>21</slash:comments>
		
		
			</item>
		<item>
		<title>کار با RecyclerView و CardView متریال دیزاین</title>
		<link>https://android-studio.ir/android-recyclerview-cardview/</link>
					<comments>https://android-studio.ir/android-recyclerview-cardview/#comments</comments>
		
		<dc:creator><![CDATA[سیدمهدی مطهری]]></dc:creator>
		<pubDate>Thu, 19 Apr 2018 19:23:22 +0000</pubDate>
				<category><![CDATA[آموزش‌های پایه]]></category>
		<category><![CDATA[رابط_کاربری]]></category>
		<category><![CDATA[رابط_کاربری_اندروید]]></category>
		<category><![CDATA[متریال_دیزاین]]></category>
		<guid isPermaLink="false">https://android-studio.ir/?p=94287</guid>

					<description><![CDATA[<p>در طراحی و توسعه برنامه‌های موبایلی و بخصوص اپلیکیشن‌های اندرویدی، استفاده از لیست‌ها کاربرد فراوانی برای نمایش اطلاعات و محتوا دارد. مانند نمایش لیست تراکنش‌های حساب شخص در یک برنامه بانکی یا نمایش لیست شهرها در یک برنامه ویژه گردشگری. در این بخش به نحوه پیاده سازی لیست ها با استفاده از RecyclerView و CardView [&#8230;]</p>
<p>نوشته <a href="https://android-studio.ir/android-recyclerview-cardview/">کار با RecyclerView و CardView متریال دیزاین</a> اولین بار در <a href="https://android-studio.ir">اندروید استودیو</a> پدیدار شد.</p>
]]></description>
										<content:encoded><![CDATA[<p>در طراحی و توسعه برنامه‌های موبایلی و بخصوص اپلیکیشن‌های اندرویدی، استفاده از لیست‌ها کاربرد فراوانی برای نمایش اطلاعات و محتوا دارد. مانند نمایش لیست تراکنش‌های حساب شخص در یک برنامه بانکی یا نمایش لیست شهرها در یک برنامه ویژه گردشگری. در این بخش به نحوه پیاده سازی لیست ها با استفاده از RecyclerView و CardView در اندروید می پردازیم که شامل مباحث زیر می باشد:</p>
<div class="title-box">
<b>آنچه در این آموزش می‌خوانید:</b></p>
<ul>
<li>معرفی کامپوننت RecyclerView و بررسی مزایای آن نسبت به ListView</li>
<li>آشنایی با کلاس Model</li>
<li>آشنایی با ViewHolder</li>
<li>آشنایی با Adapter در RecyclerView و متدهای آن</li>
<li>ساخت یک لیست و نمایش آن در قالب آیتم‌های یک RecyclerView</li>
<li>کار با متدهای LinearLayoutManager، GridLayoutManager و StaggeredGridLayoutManager جهت تعیین نحوه چیدمان آیتم‌ها</li>
<li>آشنایی با کامپوننت CardView و نحوه استفاده از آن در پروژه و طراحی لایه ها</li>
</ul>
</div>
<p class="copy">این مبحث در قالب PDF و در ۴۸ صفحه تهیه شده که در ادامه چند صفحه‌ی ابتدایی آن را مشاهده می کنید:</p>
<p></p>
<h2>معرفی RecyclerView:</h2>
<p>به نام خدا. در فصل پنجم با کامپوننت/ویجت <a href="http://android-studio.ir/android-listview/" target="_blank" rel="noopener noreferrer">ListView</a> آشنا شدیم. از ListView برای نمایش آیتم ها در قالب یک لیست استفاده کردیم. با معرفی متریال دیزاین در اندروید، ViewGroup یا ویجت RecyclerView نیز به عنوان یک جایگزین حرفه ای برای ListView و GridView معرفی شد. RecyclerView مزیت هایی نسبت به ListView دارد از جمله:<br />
&#8211;	بهینه است و حافظه بهتر مدیریت می شود. در RecyclerView فقط آیتم هایی که در صفحه نمایش قرار گرفته اند (به همراه چند آیتم قبل و بعد آنها) روی حافظه بارگزاری می شود نه همه آیتم های لیست.<br />
&#8211;	مدیریت RecyclerView ساده تر است و به راحتی می توان نحوه چینش آیتم ها (افقی یا عمودی) و همچنین در صورت نیاز به ستون بندی، تعداد ستونها را تعیین کرد.<br />
&#8211;	در RecyclerView امکان پیاده سازی انیمیشن برای زیباتر شدن نحوه اضافه و یا حذف شدن آیتم ها فراهم شده است.</p>
<p><a href="http://android-studio.ir/android-recyclerview-cardview/" target="_blank" rel="noopener noreferrer">RecyclerView</a> لیستی از آیتم ها را نمایش می دهد که قابل Scroll بوده و محدودیتی در تعداد آیتم ها ندارد. از نمونه های کاربردی می توان به پیام رسان ها، لیست مخاطبین تلفن همراه، لیست ایمیل‌ها و یا لیست شهرها به همراه اطلاعات آب و هوایی مربوط به آنها در یک اپلیکیشن هواشناسی اشاره کرد.</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/recycle/recyclerview_list_mail.png" alt="نمایش لیست ایمیل توسط RecyclerView" /></p>
<p>تصویر بالا یک اپ مدیریت ایمیل است که هر آیتم از لیست شامل عنوان، نام فرستنده و چند کلمه ابتدای متن ایمیل می باشد. در سمت راست نیز زمان دریافت و آیکون ستاره جهت علامت زدن موارد مهم قرار دارد.</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/recycle/whatsapp_recyclerview_example.png" alt="نمایش لیست ایمیل توسط RecyclerView" /></p>
<p>تصویر بالا مربوط به پیام رسان WhatsApp است. اینجا هم مانند مثال قبل، آیتم های لیست دارای عناصر مشترکی هستند. یک تصویر پروفایل، نام شخص و چند کلمه ابتدای پیغام دریافتی. در سمت راست نیز زمان دریافت پیغام مشخص شده است.<br />
برای ساخت و نمایش لیست ها در RecyclerView مانند ListView ابتدا باید یک قالب کلی برای نمایش یک آیتم طراحی کنیم. سپس اطلاعاتی که قصد نمایش آنها در قالب لیست داریم را یک به یک به قالب از قبل طراحی شده می‌فرستیم تا همگی با یک فرمت و ظاهر مشخص و یکسان نمایش داده شوند.<br />
بنابراین در RecyclerView امکان شخصی سازی را داریم و آیتم ها از ساده ترین حالت یعنی یک text تا یک آیتم پیچیده (ترکیبی از تصویر، متن، لینک و&#8230;) قابل پیاده سازی هستند. داده ها از منابعی مانند آرایه ها،دیتابیس، سرور و&#8230; به RecyclerView منتقل و نمایش داده می شوند.<br />
توصیه می کنم قبل از مطالعه این مبحث حتما یکبار مبحث ListView را نیز مطالعه و تمرین کنید تا تفاوت بین این دو ویجت بهتر برایتان ملموس شود. ضمن اینکه برخی از جزئیات که در هردو مبحث مشترک است را در اینجا بطور خلاصه بیان می کنم.<br />
در اندروید استودیو یک پروژه جدید با نام RecyclerView و یک Empty Activity ایجاد می کنم. برای استفاده از RecyclerView باید کتابخانه آنرا به پروژه اضافه کنیم که از کتابخانه های متعلق به support است. مطابق مباحث گذشته، کتابخانه را به دو صورت اضافه کردن دستی به فایل build.gradle و یا مسیر:</p>
<p style="text-align: left; direction: ltr;">
File > Project Structure > Modules (app) > Dependencies > + > Library Dependency
</p>
<p>به پروژه اضافه می کنم:</p>
<pre class="brush: java; title: ; notranslate">
dependencies {
    implementation fileTree(include: &#x5B;'*.jar'], dir: 'libs')
    implementation 'com.android.support:appcompat-v7:27.0.2'
    implementation 'com.android.support:recyclerview-v7:27.0.2'
}
</pre>
<p>پس از سینک شدن موفق پروژه، یک ویجت/کامپوننت از نوع RecyclerView در لایه اکتیویتی اصلی پروژه یعنی activity_main.xml تعریف می کنم:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;RelativeLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    tools:context=&quot;ir.android_studio.recyclerview.MainActivity&quot;&gt;

    &lt;android.support.v7.widget.RecyclerView
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        android:id=&quot;@+id/recycler_view&quot;/&gt;

&lt;/RelativeLayout&gt;
</pre>
<p>سپس RecyclerView را به فایل جاوا اکتیویتی اضافه می کنم:</p>
<p>MainActivity.java:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.recyclerview;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.RecyclerView;

public class MainActivity extends AppCompatActivity {

    RecyclerView myRecycler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        myRecycler = findViewById(R.id.recycler_view);

    }
}
</pre>
<div class="alert alert-warning">
<span class="notice">نکته:</span> در نسخه ۳ اندروید استودیو و به بعد، عمل Casting در تعریف کردن view ها در کلاس جاوا الزامی نیست. با اینحال چنانچه با ارور مواجه شدید لازم است Casting را انجام دهید. یعنی در اینجا باید (RecyclerView) به قبل از findViewById اضافه شود:</p>
<pre class="brush: java; title: ; notranslate">
myRecycler = (RecyclerView) findViewById(R.id.recycler_view);
</pre>
</div>
<p>مانند مبحث ListView برای مدیریت ویجت / view ها و ارتباط آنها با عملگرهای جاوا، از کلاسی استفاده می کنیم که اصطلاحا Model نامیده می شود. استفاده از چنین کلاسی الزامی نیست اما باعث می شود مدیریت بهتری روی پروژه داشته باشیم. در کلاس Model از متدهایی که اصطلاحا Getter و Setter نامیده می شوند برای مقداردهی به متغیرها و یا مقدارگیری از آنها استفاده می شود.<br />
برای ساخت Model، یک کلاس با نام دلخواه Item به پکیج اصلی پروژه اضافه می کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/recycle/add_model_java_class_to_project.png" alt="اضافه کردن کلاس Model به پروژه اندروید" /></p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.recyclerview;

public class Item {

    private int uAvatar;
    private String uName;
    private String uMessage;
    private String uTime;

}
</pre>
<p>می خواهم هر یک از آیتم های RecyclerView حاوی یک تصویر پروفایل، نام، متن پیغام و تاریخ ارسال باشد.<br />
چهار متغیر در کلاس تعریف کردم که یکی برای نمایش تصویر شخص و سه مورد دیگر برای نمایش نام، متن پیغام و تاریخ استفاده خواهد شد. در ادامه متدهای سازنده (Constructor) و همچنین Getter &#038; Setter را به کلاس مدل اضافه می کنم:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.recyclerview;

public class Item {

    private int uAvatar;
    private String uName;
    private String uMessage;
    private String uTime;

    public Item(int uAvatar, String uName, String uMessage, String uTime) {
        this.uAvatar = uAvatar;
        this.uName = uName;
        this.uMessage = uMessage;
        this.uTime = uTime;
    }

    public int getuAvatar() {
        return uAvatar;
    }

    public void setuAvatar(int uAvatar) {
        this.uAvatar = uAvatar;
    }

    public String getuName() {
        return uName;
    }

    public void setuName(String uName) {
        this.uName = uName;
    }

    public String getuMessage() {
        return uMessage;
    }

    public void setuMessage(String uMessage) {
        this.uMessage = uMessage;
    }

    public String getuTime() {
        return uTime;
    }

    public void setuTime(String uTime) {
        this.uTime = uTime;
    }
    
}
</pre>
<p>جزئیات مربوط به نحوه افزودن این متدها به کلاس را در مبحث ListView توضیح داده ام.<br />
در ابتدای مبحث گفتیم برای نمایش آیتم های لیست از یک قالب مشترک استفاده می شود که هر آیتم با همان فرمت و چینش طراحی به RecyclerView فرستاده می شود. من دقیقا همان قالبی که در مبحث ListView (لیست سفارشی) طراحی کرده بودم را در این پروژه استفاده می کنم. یک فایل با نام list_item به دایرکتوری layout پروژه اضافه می کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/recycle/add_recyclerview_item_layout_to_project.png" alt="ساخت layout نمایش آیتم RecyclerView" /></p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;LinearLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;100dp&quot;
    android:padding=&quot;5dp&quot;
    android:orientation=&quot;horizontal&quot;&gt;

    &lt;ImageView
        android:id=&quot;@+id/img_avatar&quot;
        android:layout_width=&quot;0dp&quot;
        android:layout_height=&quot;match_parent&quot;
        android:layout_weight=&quot;0.2&quot;
        android:src=&quot;@drawable/avatar_1&quot; /&gt;

    &lt;LinearLayout
        android:layout_width=&quot;0dp&quot;
        android:layout_height=&quot;match_parent&quot;
        android:layout_weight=&quot;0.8&quot;
        android:orientation=&quot;vertical&quot;&gt;

        &lt;LinearLayout
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;0dp&quot;
            android:layout_weight=&quot;0.5&quot;
            android:orientation=&quot;horizontal&quot;&gt;

            &lt;TextView
                android:id=&quot;@+id/txt_name&quot;
                android:layout_width=&quot;0dp&quot;
                android:layout_height=&quot;match_parent&quot;
                android:layout_weight=&quot;1&quot;
                android:gravity=&quot;bottom&quot;
                android:paddingLeft=&quot;5dp&quot;
                android:text=&quot;Name&quot; /&gt;

            &lt;TextView
                android:id=&quot;@+id/txt_time&quot;
                android:layout_width=&quot;0dp&quot;
                android:layout_height=&quot;match_parent&quot;
                android:layout_weight=&quot;1&quot;
                android:gravity=&quot;bottom|right&quot;
                android:text=&quot;Time&quot; /&gt;
        &lt;/LinearLayout&gt;

        &lt;TextView
            android:id=&quot;@+id/txt_message&quot;
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;0dp&quot;
            android:layout_marginTop=&quot;5dp&quot;
            android:layout_weight=&quot;0.5&quot;
            android:paddingLeft=&quot;5dp&quot;
            android:text=&quot;Message&quot;
            android:textColor=&quot;#161111&quot; /&gt;

    &lt;/LinearLayout&gt;

&lt;/LinearLayout&gt;
</pre>
<p>این لایه شامل یک ImageView و سه TextView است. یک تصویر هم در دایرکتوری drawable برای نمایش مکان آواتار در قسمت Preview اندروید استودیو قرار دادم.خروجی list_item.xml در بخش پیش نمایش به اینصورت است:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/recycle/recycler_item_layout_preview.png" alt="پیش نمایش لایه آیتم RecyclerView" /></p>
<p>در مرحله بعد برای مدیریت view ها و ارسال داده های دریافتی (شامل آدرس تصویر پروفایل، نام، متن پیغام و تاریخ) به آنها، نیاز به ساخت یک کلاس Adapter داریم. بنابراین یک کلاس دیگر با نام دلخواه ItemAdapter به پکیج اصلی پروژه اضافه می کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/recycle/add_recyclerview_adapter_class_to_project.png" alt="ساخت کلاس Adapter برای RecyclerView" /></p>
<p>اگر بخاطر داشته باشید در ListView برای بهینه تر شدن برنامه، یک ViewHolder تعریف کردیم. در RecyclerView هم این مورد درون کتابخانه تعبیه شده و برای تعریف view ها باید از ViewHolder استفاده کنیم. داخل کلاس آداپتر قبل از هرکار ابتدا یک کلاس داخلی (inner class) برای ViewHolder ایجاد و آنرا تکمیل می کنم:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.recyclerview;

import android.support.v7.widget.RecyclerView;

public class ItemAdapter {

    public class MyViewHolder extends RecyclerView.ViewHolder {}

}
</pre>
<p>یک کلاس داخلی با نام دلخواه MyViewHolder به کلاس ItemAdapter اضافه کردم. این کلاس باید از کلاس ViewHolder ارث بری شود و با توجه به اینکه ViewHolder در کتابخانه RecyclerView تعریف شده، کلاس را باید از RecyclerView.ViewHolder ارث بری کنیم.<br />
View ها را داخل MyViewHolder تعریف می کنم:</p>
<pre class="brush: java; title: ; notranslate">
public class MyViewHolder extends RecyclerView.ViewHolder {

    public ImageView aAvatar;
    public TextView aName;
    public TextView aMessage;
    public TextView aTime;

}
</pre>
<p>در بدنه کلاس MyViewHolder خطایی مشاهده می شود که با قراردادن نشانگر روی آن و زدن alt+Enter از ما می خواهد متد سازنده را به کلاس اضافه کنیم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/recycle/add_ViewHolder_constructor.png" alt="متد سازنده ViewHolder" /></p>
<pre class="brush: java; title: ; notranslate">
public class MyViewHolder extends RecyclerView.ViewHolder {

    public ImageView aAvatar;
    public TextView aName;
    public TextView aMessage;
    public TextView aTime;


    public MyViewHolder(View itemView) {
        super(itemView);
    }
}
</pre>
<p>حالا view ها را درون متد سازنده به متغیر مربوط به خودشان متصل می کنم:</p>
<pre class="brush: java; title: ; notranslate">
public class MyViewHolder extends RecyclerView.ViewHolder {

    public ImageView aAvatar;
    public TextView aName;
    public TextView aMessage;
    public TextView aTime;


    public MyViewHolder(View itemView) {
        super(itemView);
        
        aAvatar = itemView.findViewById(R.id.img_avatar);
        aName = itemView.findViewById(R.id.txt_name);
        aMessage = itemView.findViewById(R.id.txt_message);
        aTime = itemView.findViewById(R.id.txt_time);
    }
}
</pre>
<p>ملاحظه می کنید در اینجا قبل از findViewById به واسطه itemView که از جنس View است تعریف شده و به تنهایی نمی توان استفاده کرد. در واقع itemView شامل هریک از آیتم های RecyclerView می باشد. فعلا با MyViewHolder کاری ندارم.<br />
پس از ساخت ViewHolder، لازم است کلاس ItemAdapter از RecyclerView.Adapter ارث بری شود:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/recycle/extends_from_recyclerview_adapter.png" alt="ارث بری کلاس Adapter از RecyclerView.Adapter" /></p>
<p>مشاهده می کنید در لیست پیشنهادی، در مقابل Adapter عبارت VH (مخفف ViewHolder) قید شده به این معنی که در اینجا باید کلاسی که از ViewHolder اصطلاحا کاستوم کردیم را وارد کنیم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/recycle/extends_from_recyclerview_adapter_2.png" alt="ارث بری کلاس Adapter از RecyclerView.Adapter" /></p>
<p>در نهایت کلاس به اینصورت تکمیل می شود:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.recyclerview;

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

public class ItemAdapter extends RecyclerView.Adapter&lt;ItemAdapter.MyViewHolder&gt; {

    public class MyViewHolder extends RecyclerView.ViewHolder {

        public ImageView aAvatar;
        public TextView aName;
        public TextView aMessage;
        public TextView aTime;


        public MyViewHolder(View itemView) {
            super(itemView);

            aAvatar = itemView.findViewById(R.id.img_avatar);
            aName = itemView.findViewById(R.id.txt_name);
            aMessage = itemView.findViewById(R.id.txt_message);
            aTime = itemView.findViewById(R.id.txt_time);
        }
    }

}
</pre>
<p>مجدد در بدنه کلاس اصلی هم خطا میگیرم که با alt+Enter متدهای ضروری Adapter را اضافه می کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/recycle/implement_adapter_methods.png" alt="متدهای Adapter" /></p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/recycle/implement_adapter_methods_2.png" alt="متدهای Adapter" /></p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.recyclerview;

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

public class ItemAdapter extends RecyclerView.Adapter&lt;ItemAdapter.MyViewHolder&gt; {

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return null;
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {

    }

    @Override
    public int getItemCount() {
        return 0;
    }

    public class MyViewHolder extends RecyclerView.ViewHolder {

        public ImageView aAvatar;
        public TextView aName;
        public TextView aMessage;
        public TextView aTime;


        public MyViewHolder(View itemView) {
            super(itemView);

            aAvatar = itemView.findViewById(R.id.img_avatar);
            aName = itemView.findViewById(R.id.txt_name);
            aMessage = itemView.findViewById(R.id.txt_message);
            aTime = itemView.findViewById(R.id.txt_time);
        }
    }

}
</pre>
<p class="pdfdl">جهت مطالعه ادامه آموزش، فایل PDF را دانلود نمائید</p>
<p class="source">توجه : سورس پروژه داخل پوشه Exercises قرار داده شده است.</p>
<p class="copy">با توجه به اینکه آموزشهای پایه با قیمت پایین در اختیار کاربر قرار گرفته و درآمد حاصل صرف تامین هزینه های وب سایت و تهیه آموزش های آتی می شود، به اشتراک گذاری این فایل با دیگران خلاف اخلاق خواهد بود.</p>
<div class="alert dlbox">
<span class="title"><i class="titleicon fa fa-download fa-lg"></i>دانلود نسخه کامل این آموزش به همراه سورس پروژه</span><br />
<i class="dlicon fa fa-square fa-lg"></i> تعداد صفحات : ۴۸<br />
<i class="dlicon fa fa-square fa-lg"></i> حجم : ۴ مگابایت<br />
<i class="dlicon fa fa-square fa-lg"></i> قیمت : ۱۸ هزار تومان<br />
<span class="notice">توجه: صرفا در صورتی از درگاه پشتیبان استفاده کنید که قادر به پرداخت از طریق سبد دانلود نباشید.</span><br />
<a href="https://android-studio.ir/checkout/?edd_action=add_to_cart&#038;download_id=94288" class="button green edd-submit" rel="noopener noreferrer"><i class="titleicon fa fa-shopping-cart fa-lg"></i>افزودن به سبد دانلود</a> <a href="https://atisdesign.ir/android-files/" class="button red edd-submit" target="_blank" rel="noopener noreferrer">درگاه پشتیبان</a>
</div>
<p>نوشته <a href="https://android-studio.ir/android-recyclerview-cardview/">کار با RecyclerView و CardView متریال دیزاین</a> اولین بار در <a href="https://android-studio.ir">اندروید استودیو</a> پدیدار شد.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://android-studio.ir/android-recyclerview-cardview/feed/</wfw:commentRss>
			<slash:comments>49</slash:comments>
		
		
			</item>
		<item>
		<title>پیاده سازی Tab توسط TabLayout و ViewPager متریال دیزاین</title>
		<link>https://android-studio.ir/android-tab-with-tablayout-viewpager/</link>
					<comments>https://android-studio.ir/android-tab-with-tablayout-viewpager/#comments</comments>
		
		<dc:creator><![CDATA[سیدمهدی مطهری]]></dc:creator>
		<pubDate>Fri, 09 Feb 2018 15:28:45 +0000</pubDate>
				<category><![CDATA[آموزش‌های پایه]]></category>
		<category><![CDATA[رابط_کاربری_اندروید]]></category>
		<category><![CDATA[متریال_دیزاین]]></category>
		<guid isPermaLink="false">https://android-studio.ir/?p=83706</guid>

					<description><![CDATA[<p>در این بخش به نحوه پیاده سازی Tab ها با استفاده از Fragment و ویجت های TabLayout و ViewPager در اندروید می پردازیم که شامل مباحث زیر می باشد: آنچه در این آموزش می‌خوانید: معرفی Tab (تب) متریال در اندروید معرفی کامپوننت TabLayout معرفی کامپوننت ViewPager ساخت یک کلاس برای مدیریت فرگمنت ها و عنوان [&#8230;]</p>
<p>نوشته <a href="https://android-studio.ir/android-tab-with-tablayout-viewpager/">پیاده سازی Tab توسط TabLayout و ViewPager متریال دیزاین</a> اولین بار در <a href="https://android-studio.ir">اندروید استودیو</a> پدیدار شد.</p>
]]></description>
										<content:encoded><![CDATA[<p>در این بخش به نحوه <a href="http://android-studio.ir/android-tab-with-tablayout-viewpager/" target="_blank" rel="noopener noreferrer">پیاده سازی Tab</a> ها با استفاده از Fragment و ویجت های <a href="http://android-studio.ir/android-tab-with-tablayout-viewpager/" target="_blank" rel="noopener noreferrer">TabLayout</a> و <a href="http://android-studio.ir/android-tab-with-tablayout-viewpager/" target="_blank" rel="noopener noreferrer">ViewPager</a> در اندروید می پردازیم که شامل مباحث زیر می باشد:</p>
<div class="title-box">
<b>آنچه در این آموزش می‌خوانید:</b></p>
<ul>
<li>معرفی Tab (تب) متریال در اندروید</li>
<li>معرفی کامپوننت TabLayout</li>
<li>معرفی کامپوننت ViewPager</li>
<li>ساخت یک کلاس برای مدیریت فرگمنت ها و عنوان تب ها در ViewPager و TabLayout</li>
<li>نحوه اضافه کردن عنوان (text) به Tab ها</li>
<li>نحوه اضافه کردن آیکون به Tab ها</li>
<li>نمایش همزمان آیکون و تکست در تب ها</li>
<li>ویرایش تب ها مانند تغییر رنگ text، رنگ نوار پایین Tab و&#8230;</li>
<li>کاربرد خاصیت های tabGravity و tabMode در TabLayout</li>
</ul>
</div>
<p class="copy">این مبحث در قالب PDF و در ۲۹ صفحه تهیه شده که در ادامه چند صفحه ی ابتدایی آن را مشاهده می کنید:</p>
<p></p>
<h2>آشنایی با Tab (تب) ها در اندروید:</h2>
<p>بنام خدا. Tab ها تقریبا در همه پلتفرم ها و برنامه ها استفاده می شوند. در سیستم عامل ویندوز وقتی یک پنجره تنظیمات را باز می کنید، در بالای پنجره چندین Tab تعبیه شده که با انتخاب هرکدام، به تعدادی از گزینه های مرتبط با عنوان آن تب دسترسی خواهید داشت. یا مثال ساده تر، در مرورگرهای وب مانند کروم و فایرفاکس، برای مشاهده هر وب سایت یک تب (Tab) جدید باز می کنیم. در سایر پلتفرم ها و نرم افزارها هم به همینصورت از Tab ها استفاده می شود. از جمله در سیستم عامل و نرم افزارهای اندروید.<br />
اولین مثالی که به ذهنم رسید پیام رسان WhatsApp است:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/tabs/whatsapp_tablayout_viewpager.png" alt="مثال اپلیکیشن اندرویدی WhatsApp برای استفاده TabLayout و ViewPager" /></p>
<p>در زیر Toolbar سه Tab به نام‌های Calls، Chats و Contacts تعریف شده که با انتخاب هر یک از تب ها، محتوا و لیست مرتبط با آن نمایش داده می شود.</p>
<h2>معرفی TabLayout در متریال دیزاین</h2>
<p>TabLayout یکی دیگر از ویجت (کامپوننت) هایی است که اندروید در متریال دیزاین معرفی کرده و در کتابخانه design در دسترس است. با استفاده از ویجت TabLayout امکان تعریف و مدیریت Tab ها فراهم می شود (یعنی گزینه های Calls، Chats و Contacts در مثال بالا).</p>
<h2>ViewPager چیست؟</h2>
<p>ViewPager ویجت دیگری است که با استفاده از <a href="http://android-studio.ir/android-fragments/" target="_blank" rel="noopener noreferrer">Fragment</a> ها، می تواند چندین فرگمنت را در یک اکتیویتی نمایش دهد که با کشیدن صفحه به چپ یا راست و یا انتخاب Tab ها در TabLayout، فرگمنت ها به ترتیبی که تعیین کرده ایم نمایش داده می شوند (لیست چت ها، مکالمات و مخاطبین در مثال بالا).<br />
یعنی در اپلیکیشن WhatsApp علاوه بر اینکه با لمس هریک از تب ها، به محتوای آن (یعنی فرگمنت مرتبط با آن تب) دسترسی داریم، با کشیدن فرگمنت ها به دو طرف نیز تب ها جابجا می شوند.</p>
<p>یک پروژه با نام Tabs ایجاد می کنم و با توجه به اینکه در زمان تهیه این آموزش، اکثر دیوایس ها از API 17 و به بالا پشتیبانی می کنند، MinSDK را روی ۱۷ تنظیم می کنم. همانطور که در ابتدا اشاره شد، لازم است کتابخانه design را به پروژه اضافه کنیم:</p>
<pre class="brush: java; title: ; notranslate">
dependencies {

    implementation 'com.android.support:appcompat-v7:27.0.2'
    implementation 'com.android.support:design:27.0.2'
}
</pre>
<p>در مرحله اول، ActionBar پیش فرض پروژه را مطابق آنچه در <a href="http://android-studio.ir/android-toolbar-actionbar/" target="_blank" rel="noopener noreferrer">آموزش تولبار</a> بیان شد، حذف کرده و Toolbar متریال را جایگزین می کنم:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;LinearLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    android:orientation=&quot;vertical&quot;
    tools:context=&quot;ir.android_studio.tabs.MainActivity&quot;&gt;

    &lt;android.support.v7.widget.Toolbar
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;?attr/actionBarSize&quot;
        android:id=&quot;@+id/m_toolbar&quot;
        android:background=&quot;?attr/colorPrimary&quot;
        android:elevation=&quot;3dp&quot;
        app:theme=&quot;@style/ThemeOverlay.AppCompat.Dark.ActionBar&quot;&gt;

    &lt;/android.support.v7.widget.Toolbar&gt;

&lt;/LinearLayout&gt;
</pre>
<p>من لایه را به LinearLayout از نوع vertical تغییر دادم تا ویجت هایی که اضافه می کنم زیر یکدیگر قرار بگیرند. البته پیاده سازی با RelativeLayout یا CoordinatorLayout نیز امکان پذیر است.</p>
<p>MainActivity.java:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.tabs;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;

public class MainActivity extends AppCompatActivity {

    Toolbar mToolbar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mToolbar =  findViewById(R.id.m_toolbar);
        setSupportActionBar(mToolbar);

    }
}
</pre>
<p>قبل از ادامه کار، پروژه را اجرا می کنم تا مطمئن شوم تولبار به اکتیویتی اضافه شده است:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/tabs/add_material_toolbar_to_project.png" alt="اضافه کردن Toolbar به پروژه" /></p>
<p>در ادامه، چند فرگمنت ساده به پروژه اضافه می کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/tabs/fragments_added_to_project.png" alt="اضافه کردن فرگمنت به پروژه اندرویدی" /></p>
<p>سه فرگمنت با نام‌های FragmentOne، FragmentTwo و FragmentThree به پروژه اضافه شد که در layout هر فرگمنت یک TextView وجود دارد. مانند fragment_one.xml:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;FrameLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    tools:context=&quot;ir.android_studio.tabs.FragmentOne&quot;&gt;

    &lt;TextView
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        android:gravity=&quot;center&quot;
        android:text=&quot;Fragment One&quot;
        android:textSize=&quot;30sp&quot;/&gt;

&lt;/FrameLayout&gt;
</pre>
<p>مجدد main_activity.xml را باز کرده و به صورت زیر دو تگ TabLayout و ViewPager را به لایه اضافه می کنم:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;LinearLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    android:orientation=&quot;vertical&quot;
    tools:context=&quot;ir.android_studio.tabs.MainActivity&quot;&gt;

    &lt;android.support.v7.widget.Toolbar
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;?attr/actionBarSize&quot;
        android:id=&quot;@+id/m_toolbar&quot;
        android:background=&quot;?attr/colorPrimary&quot;
        android:elevation=&quot;3dp&quot;
        app:theme=&quot;@style/ThemeOverlay.AppCompat.Dark.ActionBar&quot;&gt;

    &lt;/android.support.v7.widget.Toolbar&gt;

    &lt;android.support.design.widget.TabLayout
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:id=&quot;@+id/tab_layout&quot;
        android:background=&quot;?attr/colorPrimary&quot; /&gt;

    &lt;android.support.v4.view.ViewPager
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        android:id=&quot;@+id/view_pager&quot; /&gt;

&lt;/LinearLayout&gt;
</pre>
<p>فایل colors.xml:</p>
<pre class="brush: xml; title: ; notranslate">
xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;resources&gt;
    &lt;color name=&quot;colorPrimary&quot;&gt;#009688&lt;/color&gt;
    &lt;color name=&quot;colorPrimaryDark&quot;&gt;#00796B&lt;/color&gt;
    &lt;color name=&quot;colorAccent&quot;&gt;#FFC107&lt;/color&gt;
&lt;/resources&gt;
</pre>
<p>برای TabLayout رنگ پس زمینه یکسان با Toolbar تعریف کردم تا به صورت یکپارچه نمایش داده شوند.</p>
<p>TabLayout و ViewPager را در اکتیویتی تعریف می کنم:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.tabs;

import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;

public class MainActivity extends AppCompatActivity {

    Toolbar mToolbar;
    TabLayout tbLayout;
    ViewPager vPager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mToolbar =  findViewById(R.id.m_toolbar);
        setSupportActionBar(mToolbar);

        vPager = findViewById(R.id.view_pager);
        tbLayout = findViewById(R.id.tab_layout);

    }
}
</pre>
<p>در ادامه برای مدیریت و نمایش فرگمنت ها یک کلاس جدید با نام دلخواه ViewPagerAdapter به پروژه اضافه می کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/tabs/add_ViewPagerAdapter_class_to_project.png" alt="ساخت کلاس ViewPagerAdapter برای مدیریت فرگمنت ها و tabLayout" /></p>
<p>ViewPagerAdapter.java:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.tabs;


public class ViewPagerAdapter {

}
</pre>
<p>سپس این کلاس را از FragmentPagerAdapter ارث بری می کنم. FragmentPagerAdapter به یک import نیاز دارد که همانند گذشته با Alt + Enter انجام می دهم:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.tabs;

import android.support.v4.app.FragmentPagerAdapter;

public class ViewPagerAdapter extends FragmentPagerAdapter {

}
</pre>
<p>اندروید استودیو علامت اخطار نشان می دهد که با کلیک روی آن و انتخاب Implements Methods،  به دو متد مورد نیاز FragmentPagerAdapter به کلاس اضافه می شود.</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/tabs/add_methods_to_FragmentPagerAdapter.png" alt="افزودن متدهای FragmentPagerAdapter" /></p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/tabs/add_methods_to_FragmentPagerAdapter_2.png" alt="افزودن متدهای FragmentPagerAdapter" /></p>
<p>سپس اخطار دیگری می‌گیرم مبنی بر اینکه یک Constructor (متد سازنده) نیز باید اضافه شود:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/tabs/add_constructor_to_class.png" alt="اضافه کردن متد سازنده Constructor به کلاس" /></p>
<p>در نهایت کلاس به اینصورت تکمیل می شود:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.tabs;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

public class ViewPagerAdapter extends FragmentPagerAdapter {

    public ViewPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        return null;
    }

    @Override
    public int getCount() {
        return 0;
    }
}
</pre>
<p>من به دو List نیاز دارم. یکی برای تعریف فرگمنت ها و دیگری برای عنوان Tab ها. پس یک List از نوع Fragment با نام دلخواه frgList و یک لیست از نوع String با نام دلخواه titleList می سازم:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.tabs;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

import java.util.ArrayList;
import java.util.List;

public class ViewPagerAdapter extends FragmentPagerAdapter {

    private final List&lt;Fragment&gt; frgList = new ArrayList&lt;&gt;();
    private final List&lt;String&gt; titleList = new ArrayList&lt;&gt;();
    
    public ViewPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        return null;
    }

    @Override
    public int getCount() {
        return 0;
    }
}
</pre>
<p><span class="label label-primary">تصویر نهایی خروجی پروژه این مبحث آموزشی:</span></p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/tabs/add_icon_to_tabs.png" alt="تصویر نهایی پروژه" /></p>
<p class="pdfdl">جهت مطالعه ادامه آموزش، فایل PDF را دانلود نمائید</p>
<p class="source">توجه : سورس پروژه داخل پوشه Exercises قرار داده شده است.</p>
<p class="copy">با توجه به اینکه آموزشهای پایه با قیمت پایین در اختیار کاربر قرار گرفته و درآمد حاصل صرف تامین هزینه های وب سایت و تهیه آموزش های آتی می شود، به اشتراک گذاری این فایل با دیگران خلاف اخلاق خواهد بود.</p>
<div class="alert dlbox">
<span class="title"><i class="titleicon fa fa-download fa-lg"></i>دانلود نسخه کامل این آموزش به همراه سورس پروژه</span><br />
<i class="dlicon fa fa-square fa-lg"></i> تعداد صفحات : ۲۹<br />
<i class="dlicon fa fa-square fa-lg"></i> حجم : ۲ مگابایت<br />
<i class="dlicon fa fa-square fa-lg"></i> قیمت : ۱۶ هزار تومان<br />
<span class="notice">توجه: صرفا در صورتی از درگاه پشتیبان استفاده کنید که قادر به پرداخت از طریق سبد دانلود نباشید.</span><br />
<a href="https://android-studio.ir/checkout/?edd_action=add_to_cart&#038;download_id=83707" class="button green edd-submit" rel="noopener noreferrer"><i class="titleicon fa fa-shopping-cart fa-lg"></i>افزودن به سبد دانلود</a> <a href="https://atisdesign.ir/android-files/" class="button red edd-submit" target="_blank" rel="noopener noreferrer">درگاه پشتیبان</a>
</div>
<p>نوشته <a href="https://android-studio.ir/android-tab-with-tablayout-viewpager/">پیاده سازی Tab توسط TabLayout و ViewPager متریال دیزاین</a> اولین بار در <a href="https://android-studio.ir">اندروید استودیو</a> پدیدار شد.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://android-studio.ir/android-tab-with-tablayout-viewpager/feed/</wfw:commentRss>
			<slash:comments>48</slash:comments>
		
		
			</item>
		<item>
		<title>کار با Snackbar متریال دیزاین</title>
		<link>https://android-studio.ir/android-material-design-snackbar/</link>
					<comments>https://android-studio.ir/android-material-design-snackbar/#comments</comments>
		
		<dc:creator><![CDATA[سیدمهدی مطهری]]></dc:creator>
		<pubDate>Thu, 01 Feb 2018 16:18:50 +0000</pubDate>
				<category><![CDATA[آموزش‌های پایه]]></category>
		<category><![CDATA[آموزش‌های رایگان]]></category>
		<category><![CDATA[رابط_کاربری_اندروید]]></category>
		<category><![CDATA[متریال_دیزاین]]></category>
		<guid isPermaLink="false">https://android-studio.ir/?p=82247</guid>

					<description><![CDATA[<p>معرفی Snackbar یا اسنک بار در اندروید: به نام خدا. Snackbar را می توان نسخه جدیدی از Toast دانست. شاید واژه &#8220;جایگزین&#8221; مناسب نباشد اما در موارد زیادی استفاده از اسنک بار به جای Toast می تواند رضایت بخش بوده و زیبایی بیشتری به اپ ما بدهد. ضمن اینکه در اسنک بار، شخصی سازی بیشتری [&#8230;]</p>
<p>نوشته <a href="https://android-studio.ir/android-material-design-snackbar/">کار با Snackbar متریال دیزاین</a> اولین بار در <a href="https://android-studio.ir">اندروید استودیو</a> پدیدار شد.</p>
]]></description>
										<content:encoded><![CDATA[<h2>معرفی Snackbar یا اسنک بار در اندروید:</h2>
<p>به نام خدا. Snackbar را می توان نسخه جدیدی از Toast دانست. شاید واژه &#8220;جایگزین&#8221; مناسب نباشد اما در موارد زیادی استفاده از اسنک بار به جای Toast می تواند رضایت بخش بوده و زیبایی بیشتری به اپ ما بدهد. ضمن اینکه در اسنک بار، شخصی سازی بیشتری در اختیار داریم.<br />
به تصویر زیر دقت کنید:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/snackbar/snackbar_example_1.png" alt="اسنک بار در متریال دیزاین اندروید" /></p>
<p>بعد از اینکه کاربر در اپلیکیشنی مانند Gmail، ایمیلی را حذف می کند، پیغام Message is deleted بجای نمایش در قالب Toast، به صورت نواری با پس زمینه تیره رنگ و به حالت انیمیشن از پایین صفحه ظاهر شده و پس از پایان زمان تعیین شده به همانصورت به طرف پایین برگشته و محو می شود.<br />
یا یک مثال دیگر از اسنک بار:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/snackbar/snackbar_example_2.png" alt="Android Material Design Snackbar" /></p>
<p>در اینجا پیغامی مبنی بر عدم دسترسی به شبکه به کاربر اعلام شده است.<br />
در هر دو مثال بالا، علاوه بر نمایش پیغام، یک Action نیز در سمت راست اضافه شده که کاربر می تواند عملی را انجام دهد. مانند لغو حذف ایمیل در مثال اول و تلاش مجدد برای اتصال به شبکه در مثال دوم. پس یکی از مزیت های اسنک بار نسب به Toast همین قابلیت اضافه کردن دکمه و اکشن است.</p>
<p>دموی یک اسنک بار:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/snackbar/snackbar_demo.gif" alt="" /></p>
<p>در ادامه به بررسی Snackbar در قالب یک پروژه می پردازم.</p>
<h2>ساخت و بررسی Snackbar:</h2>
<p>یک پروژه با نام Snackbar و MinSDK 17 در اندروید استودیو ایجاد کردم. مانند مباحث گذشته، اسنک بار نیز علاوه بر کتابخانه اصلی متریال دیزاین یعنی appcompat-v7 به کتابخانه design هم نیاز دارد:</p>
<pre class="brush: java; title: ; notranslate">
dependencies {
    implementation fileTree(dir: 'libs', include: &#x5B;'*.jar'])
    implementation 'com.android.support:appcompat-v7:27.0.2'
    implementation 'com.android.support:design:27.0.2'
}
</pre>
<p>برای اینکه قابلیت های اسنک بار به درستی اجرا شود (مانند قابلیت کشیدن به سمت راست برای از بین بردن یا swipe-to-dismiss) لازم است view ای که Snackbar در آن قرار گرفته از جنس CoordinatorLayout باشد. پس لایه اکتیویتی را به CoordinatorLayout تبدیل کرده و یک id نیز به آن اختصاص می دهم:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;android.support.design.widget.CoordinatorLayout 
xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    android:id=&quot;@+id/crd_layout&quot;
    tools:context=&quot;ir.android_studio.snackbar.MainActivity&quot;&gt;
    

&lt;/android.support.design.widget.CoordinatorLayout&gt;
</pre>
<p>فعلا با layout کاری ندارم و به تکمیل کدهای جاوای اکتیویتی می پردازم:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.snackbar;

import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    CoordinatorLayout crdLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        crdLayout = findViewById(R.id.crd_layout);

        Snackbar snkbr = Snackbar.make(crdLayout, &quot;Sample Snackbar Message&quot;, 
        Snackbar.LENGTH_LONG);
        
        snkbr.show();

    }
}
</pre>
<p>ابتدا CoordinatorLayout را با نام دلخواه crdLayout تعریف کردم. سپس یک نمونه از Snackbar با نام snkbr ساختم. همانطور که مشاهده می کنید با استفاده از تابع make که ۳ پارامتر ورودی می گیرد، اسنک بار را تکمیل می کنیم. ورودی اول همان view پدر یعنی CoordinatorLayout است. ورودی بعد، متن پیغام و سومی مدت زمان نمایش پیغام است که سه مقدار LENGTH_LONG (نمایش طولانی مدت)، LENGTH_SHORT (نمایش کوتاه مدت) و LENGTH_INDEFINITE را می پذیرد. استفاده از مقدار LENGTH_INDEFINITE باعث می شود تا زمانی که کاربر اقدام به بستن Snackbar نکند (مانند کشیدن به سمت راست یا تایید اکشن موجود در اسنک بار) پیغام روی صفحه باقی بماند. در نهایت توسط متد show() اسنک بار نمایش داده می شود.<br />
پروژه را اجرا می کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/snackbar/snackbar.png" alt="اجرای Snackbar" /></p>
<p>به محض اجرای پروژه، اسنک بار نیز ظاهر شده و پس از چند ثانیه از صفحه حذف می شود. برای راحتتر شدن کار، اسنک بار را درون یک دکمه قرار می دهم تا با هر بار لمس دکمه، اجرا شود. به جای Button عادی از یک Floating Action Button استفاده می کنم تا یکی از اهمیت های استفاده از CoordinatorLayout را نیز در این مبحث درک کنید. FAB <a href="http://android-studio.ir/android-floating-action-button/" target="_blank" rel="noopener noreferrer">مبحث گذشته</a> را به پروژه اضافه می کنم:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;android.support.design.widget.CoordinatorLayout 
xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    android:id=&quot;@+id/crd_layout&quot;
    tools:context=&quot;ir.android_studio.snackbar.MainActivity&quot;&gt;

    &lt;android.support.design.widget.FloatingActionButton
        android:id=&quot;@+id/fab&quot;
        android:layout_width=&quot;wrap_content&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:layout_gravity=&quot;bottom|start&quot;
        android:layout_margin=&quot;16dp&quot;
        android:src=&quot;@android:drawable/ic_dialog_email&quot;
        app:backgroundTint=&quot;#2c489c&quot;
        android:clickable=&quot;true&quot;
        android:focusable=&quot;true&quot;
        app:fabSize=&quot;normal&quot;
        app:rippleColor=&quot;#b12f2f&quot;/&gt;

&lt;/android.support.design.widget.CoordinatorLayout&gt;
</pre>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.snackbar;

import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    CoordinatorLayout crdLayout;
    FloatingActionButton mFab;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        crdLayout = findViewById(R.id.crd_layout);
        mFab = findViewById(R.id.fab);

        mFab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

        Snackbar snkbr = Snackbar.make(crdLayout, &quot;Sample Snackbar Message&quot;, 
        Snackbar.LENGTH_LONG);
                snkbr.show();

            }
        });

    }
}
</pre>
<p>در واقع همان پروژه FAB است با این تفاوت که بجای Toast از Snackbar استفاده شده. پروژه را اجرا می کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/snackbar/fab_added_to_project.png" alt="اضافه کردن FloatingActionButton به پروژه" /></p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/snackbar/snackbar_run_after_fab_touch.png" alt="اجرای اسنک بار بعد از کلیک روی FAB" /></p>
<p>با لمس دکمه FAB، اسنک بار نمایش داده می شود. به تصویر دوم دقت کنید. با ظاهر شدن اسنک بار، FAB نیز به همان اندازه به بالا رفته و تداخل ایجاد نشده است در صورتی که اگر بجای CoordinatorLayout از سایر layout ها مانند RelativeLayout استفاده می کردیم، FAB در جای خود باقی می ماند و اسنک بار قسمتی از FAB را می پوشاند.</p>
<p>با استفاده از متد setDuration می توان مدت زمان نمایش اسنک بار را سفارشی کرد:</p>
<pre class="brush: java; title: ; notranslate">
mFab.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {

        Snackbar snkbr = Snackbar.make(crdLayout, &quot;Sample Snackbar Message&quot;, 
        Snackbar.LENGTH_LONG);
        snkbr.setDuration(9000);
        snkbr.show();

    }
});
</pre>
<p>در کد بالا، اسنک بار به مدت ۹ ثانیه اجرا می شود.<br />
اما در ابتدای مبحث به یکی از مهمترین برتری های <a href="http://android-studio.ir/android-material-design-snackbar/" target="_blank" rel="noopener noreferrer">Snackbar</a> نسبت به Toast اشاره شد که تعریف اکشن است:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/snackbar/add_action_to_snackbar.png" alt="اضافه کردن Action به Snackbar" /></p>
<p>متد setAction دو ورودی نیاز دارد. ورودی اول عنوان اکشن و دومی یک OnClickListener که اکشن مدنظر درون آن تعریف می گردد. به اینصورت:</p>
<pre class="brush: java; title: ; notranslate">
mFab.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {

        Snackbar snkbr = Snackbar.make(crdLayout, &quot;Sample Snackbar Message&quot;, 
        Snackbar.LENGTH_LONG);

        snkbr.setDuration(3000);

        snkbr.setAction(&quot;OK&quot;, new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                
            }
        });

        snkbr.show();

    }
});
</pre>
<p>ساده ترین اکشن، استفاده از dismiss() است. این متد قبل از به پایان رسیدن زمان نمایش <a href="http://android-studio.ir/android-material-design-snackbar/" target="_blank" rel="noopener noreferrer">اسنک بار</a> و هنگام لمس &#8220;OK&#8221; توسط کاربر، اسنک بار را می بندد. پس snkbr.dismiss() را به setAction اضافه کرده و پروژه را اجرا می کنم:</p>
<pre class="brush: java; title: ; notranslate">
snkbr.setAction(&quot;OK&quot;, new View.OnClickListener() {
    @Override
    public void onClick(View view) {

        snkbr.dismiss();

    }
});
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/snackbar/add_action_to_snackbar_2.png" alt="اضافه کردن Action به Snackbar" /></p>
<p>گزینه ای با نام OK به سمت راست اضافه شده که با لمس آن، اسنک بار بسته می شود.<br />
هر اکشن دیگری نیز می توان درنظر گرفتن. مثلا این اکشن نقش Undo را داشته باشد. یعنی در اپلیکیشن مدیریت ایمیل، بعد از نمایش پیغام &#8220;ایمیل ها حذف شد&#8221;، امکان لغو حذف وجود داشته باشد که با لمس گزینه Undo، ایمیل های حذف شده مجدد به اینباکس برگشته و پیغام جدیدی مبنی بر بازیابی ایمیل ها نمایش داده شود. </p>
<p>از setActionTextColor هم برای تغییر رنگ گزینه اکشن استفاده می شود:</p>
<pre class="brush: java; title: ; notranslate">
mFab.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {

        final Snackbar snkbr = Snackbar.make(crdLayout, &quot;Sample Snackbar Message&quot;,
        Snackbar.LENGTH_LONG);

        snkbr.setDuration(5000);

        snkbr.setAction(&quot;OK&quot;, new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                snkbr.dismiss();

            }
        });

        snkbr.setActionTextColor(Color.RED);

        snkbr.show();

    }
});
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/snackbar/change_snackbar_action_text_color.png" alt="تغییر رنگ اکشن اسنک بار" /></p>
<p>اگر بخواهیم به جای استفاده از رنگهای پیش فرض اندروید، از رنگهای تعریف شده در colors.xml استفاده کنیم به اینصورت قابل انجام است:</p>
<pre class="brush: java; title: ; notranslate">
snkbr.setActionTextColor(getResources().getColor(R.color.colorAccent));
</pre>
<p>در اینجا رنگ با نام colorAccent به setActionTextColor پاس داده می شود.</p>
<p>در نهایت رنگ متن پیغام و پس زمینه Snackbar را نیز به اینصورت تغییر می دهم:</p>
<pre class="brush: java; title: ; notranslate">
View snkView = snkbr.getView();
snkView.setBackgroundColor(Color.GRAY);

TextView txtView = snkView.findViewById(android.support.design.R.id.snackbar_text);
txtView.setTextColor(Color.GREEN);
</pre>
<p>در ابتدا یک نمونه از View با نام دلخواه snkView ساخته و snkbr.getView را درون آن قرار می دهم. به اینصورت view مربوط به snkbr به snkView متصل می شود. حالا برای تعریف رنگ پس زمینه از setBackgroundColor و رنگ متن از setTextColor استفاده شده که لازم است از TextView یک نمونه ساخته و به آی دی snackbar_text پیوند دهیم. snackbar_text در خود اندروید تعریف شده و چون مربوط به کتابخانه design است به صورت android.support.design.R.id.snackbar_text قابل دسترسی است.</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/snackbar/change_snackbar_background_and_text_color.png" alt="تغییر رنگ بک گراند و متن snackbar" /></p>
<p>MainActivity.java:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.snackbar;

import android.graphics.Color;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    CoordinatorLayout crdLayout;
    FloatingActionButton mFab;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        crdLayout = findViewById(R.id.crd_layout);
        mFab = findViewById(R.id.fab);

        mFab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

            final Snackbar snkbr = Snackbar.make(crdLayout, &quot;Sample Snackbar Message&quot;,
            Snackbar.LENGTH_LONG);

                snkbr.setDuration(5000);

                snkbr.setAction(&quot;OK&quot;, new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {

                        snkbr.dismiss();

                    }
                });

                // snkbr.setActionTextColor(Color.RED);

                snkbr.setActionTextColor(getResources().getColor(R.color.colorPrimaryDark));

                View snkView = snkbr.getView();
                snkView.setBackgroundColor(Color.GRAY);
                TextView txtView = snkView.findViewById(android.support.design.R.id.snackbar_text);
                txtView.setTextColor(Color.GREEN);

                snkbr.show();

            }
        });


    }
}
</pre>
<p style="text-align: left; direction: ltr;">
<a href="https://developer.android.com/reference/android/support/design/widget/Snackbar.html" target="_blank" rel="nofollow noopener noreferrer">https://developer.android.com/reference/android/support/design/widget/Snackbar.html</a><br />
<a href="https://material.io/guidelines/components/snackbars-toasts.html" target="_blank" rel="nofollow noopener noreferrer">https://material.io/guidelines/components/snackbars-toasts.html</a>
</p>
<p><span class="notice">توجه :</span> سورس پروژه درون پوشه Exercises قرار داده شده است</p>
<div class="alert dlbox">
<span class="title"><i class="titleicon fa fa-download fa-lg"></i>دانلود فایل این آموزش با فرمت PDF به همراه سورس پروژه</span><br />
<i class="dlicon fa fa-square fa-lg"></i> تعداد صفحات : ۱۷<br />
<i class="dlicon fa fa-square fa-lg"></i> حجم : ۱٫۲ مگابایت<br />
<i class="dlicon fa fa-square fa-lg"></i> قیمت : رایگان<br />
<a href="http://dl.android-studio.ir/courses/9_6_snackbar.zip" class="button green edd-submit">دانلود رایگان با حجم ۱٫۲ مگابایت</a> <a href="http://dl2.android-studio.ir/courses/9_6_snackbar.zip" class="button red edd-submit">لینک کمکی</a>
</div>
<p>نوشته <a href="https://android-studio.ir/android-material-design-snackbar/">کار با Snackbar متریال دیزاین</a> اولین بار در <a href="https://android-studio.ir">اندروید استودیو</a> پدیدار شد.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://android-studio.ir/android-material-design-snackbar/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
			</item>
		<item>
		<title>دکمه شناور یا Floating Action Button متریال دیزاین</title>
		<link>https://android-studio.ir/android-floating-action-button/</link>
					<comments>https://android-studio.ir/android-floating-action-button/#comments</comments>
		
		<dc:creator><![CDATA[سیدمهدی مطهری]]></dc:creator>
		<pubDate>Mon, 22 Jan 2018 16:56:35 +0000</pubDate>
				<category><![CDATA[آموزش‌های پایه]]></category>
		<category><![CDATA[آموزش‌های رایگان]]></category>
		<category><![CDATA[رابط_کاربری_اندروید]]></category>
		<category><![CDATA[متریال_دیزاین]]></category>
		<guid isPermaLink="false">https://android-studio.ir/?p=80953</guid>

					<description><![CDATA[<p>معرفی Floating Action Button: Floating Action Button یا دکمه شناور که به اختصار FAB نیز نامیده می شود یکی دیگر از کامپوننت های معرفی شده در متریال دیزاین اندروید است. همانطور که از نام آن پیداست، یک دکمه شناور است که مکان قرارگیری آن در صفحه توسط توسعه دهنده تعیین شده و با اسکرول کردن [&#8230;]</p>
<p>نوشته <a href="https://android-studio.ir/android-floating-action-button/">دکمه شناور یا Floating Action Button متریال دیزاین</a> اولین بار در <a href="https://android-studio.ir">اندروید استودیو</a> پدیدار شد.</p>
]]></description>
										<content:encoded><![CDATA[<h2>معرفی Floating Action Button:</h2>
<p>Floating Action Button یا دکمه شناور که به اختصار FAB نیز نامیده می شود یکی دیگر از کامپوننت های معرفی شده در متریال دیزاین اندروید است. همانطور که از نام آن پیداست، یک دکمه شناور است که مکان قرارگیری آن در صفحه توسط توسعه دهنده تعیین شده و با اسکرول کردن صفحه جابجا نمی شود (مگر به خواست خود توسعه دهنده). این نوع دکمه عموما در اپ هایی مانند پیام رسانها و مدیریت ایمیل استفاده می شود. مانند اپلیکیشن Gmail:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/fab/gmail_floating_action_button.jpg" alt="دکمه FloatingActionButton در جیمیل" /></p>
<p>دکمه ای دایره شکل که در سمت راست و پایین صفحه قرار گرفته و یک آیکون مداد را نشان می دهد که کاربر با لمس این دکمه به صفحه ارسال ایمیل هدایت می شود. FAB یا Floating Action Button نیز به کتابخانه appcompat و design نیاز دارد که در ادامه و در قالب یک پروژه به بررسی آن می پردازم.<br />
یک پروژه با نام FAB و MinSDK 17 ایجاد کردم. مانند مباحث قبل، از قسمت Project Structure کتابخانه design را به پروژه اضافه کرده و یا build.gradle (app) را باز کرده و به صورت دستی اینکار را انجام می دهم:</p>
<pre class="brush: java; title: ; notranslate">
dependencies {
    implementation fileTree(dir: 'libs', include: &#x5B;'*.jar'])
    implementation 'com.android.support:appcompat-v7:27.0.2'
    implementation 'com.android.support:design:27.0.2'
}
</pre>
<p>(کتابخانه های اضافی را حذف کردم)<br />
در این پروژه برای layout اصلی که FAB درون آن قرار می گیرد بجای RelativeLayout یا سایر لایه هایی که قبلا استفاده کردیم، از CoordinatorLayout استفاده می کنیم. توسط این layout مدیریت بهتری روی قسمت های مختلف (از جمله Toolbar و FAB و&#8230;) می توان انجام داد. برای این مبحث در همین حد آشنایی با CoordinatorLayout کافی است. ان شا الله پس از تکمیل مباحث متریال دیزاین، یک پروژه کامل خواهیم ساخت و تمامی مباحث عنوان شده از ابتدای آموزشها را در آن بکار خواهم برد.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;android.support.design.widget.CoordinatorLayout 
xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    tools:context=&quot;ir.android_studio.fab.MainActivity&quot;&gt;


&lt;/android.support.design.widget.CoordinatorLayout&gt;
</pre>
<p>به اینصورت، لایه activity_main.xml را به CoordinatorLayout تبدیل کردم. حالا کافیست یک تگ FloatingActionButton به صورت android.support.design.widget.FloatingActionButton به لایه اضافه کنم:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;android.support.design.widget.CoordinatorLayout 
xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    tools:context=&quot;ir.android_studio.fab.MainActivity&quot;&gt;

    &lt;android.support.design.widget.FloatingActionButton
        android:id=&quot;@+id/fab&quot;
        android:layout_width=&quot;wrap_content&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:layout_gravity=&quot;bottom|end&quot;
        android:layout_margin=&quot;16dp&quot;
        android:src=&quot;@android:drawable/ic_dialog_email&quot; /&gt;

&lt;/android.support.design.widget.CoordinatorLayout&gt;
</pre>
<p>برای layout_gravity دو مقدار bottom (پایین) و end (سمت راست) تعریف شده. layout_margin هم مقدار فاصله ای است که دکمه از کنار صفحه باید داشته باشد که مقدار استاندارد ۱۶dp است. پروژه را اجرا می کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/fab/add_floatingActionButton_to_layout.png" alt="اضافه کردن Floating Action Button به لایه" /></p>
<p>همانطور که انتظار داشتم، Floating Action Button در سمت راست و پایین صفحه با آیکونی که تعریف کرده بودم ظاهر شده است. مسلما اگر layout_gravity را به صورت زیر تغییر دهم، دکمه شناور باید به سمت چپ منتقل شود:</p>
<pre class="brush: xml; title: ; notranslate">
android:layout_gravity=&quot;bottom|start&quot;
</pre>
<p>start بر خلاف end به معنی ابتدای صفحه نمایش است. یعنی سمت چپ. دوباره اجرا می کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/fab/move_fab_to_left.png" alt="انتقال FAB به سمت چپ صفحه" /></p>
<p>رنگ بک گراند FAB به صورت پیش فرض از colorAccent تم متریال گرفته می شود که با اضافه کردن خاصیت app:backgroundTint امکان تغییر آن وجود دارد:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;android.support.design.widget.FloatingActionButton
    android:id=&quot;@+id/fab&quot;
    android:layout_width=&quot;wrap_content&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:layout_gravity=&quot;bottom|start&quot;
    android:layout_margin=&quot;16dp&quot;
    android:src=&quot;@android:drawable/ic_dialog_email&quot;
    app:backgroundTint=&quot;#2c489c&quot; /&gt;
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/fab/backgroundTint_attribute_for_fab.png" alt="تغییر رنگ بک گراند با اضافه کردن خاصیت backgroundTint به دکمه شناور FAB" /></p>
<p>آیتم های دیگری نیز جهت شخصی سازی FAB در اختیار داریم. android:clickable با مقدار true به دکمه یک انیمیشن (Ripple Animation) اضافه می کند که با لمس دکمه ایجاد می شود و کاربر حس بهتری از لمس دکمه دارد. بعد از استفاده از این خاصیت، اندروید استودیو پیغامی نشان می دهد که بهتر است در صورت استفاده از clickable، از android:focusable نیز استفاده شود:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;android.support.design.widget.FloatingActionButton
    android:id=&quot;@+id/fab&quot;
    android:layout_width=&quot;wrap_content&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:layout_gravity=&quot;bottom|start&quot;
    android:layout_margin=&quot;16dp&quot;
    android:src=&quot;@android:drawable/ic_dialog_email&quot;
    app:backgroundTint=&quot;#2c489c&quot;
    android:clickable=&quot;true&quot;
    android:focusable=&quot;true&quot;/&gt;
</pre>
<p>سایز دکمه نیز توسط خاصیت app:fabSize قابل تغییر است که دو مقدار normal و mini را می پذیرد. اگر این خاصیت روی FAB تعریف نشود به صورت پیش فرض مقدار normal اعمال خواهد شد که عموما هم ما همین اندازه را نیاز داریم. بنابراین با دادن مقدار normal به fabSize، سایز دکمه تغییری نکرده اما مقدار mini باعث کوچکتر شدن دکمه می شود:</p>
<pre class="brush: xml; title: ; notranslate">
app:fabSize=&quot;mini&quot;
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/fab/change_fab_size_to_mini.png" alt="تغییر سایز FloatingActionButton توسط fabSize" /></p>
<p>و آخرین موردی که در این مبحث به آن اشاره می کنم، خاصیت app:rippleColor است. در حالت عادی و بدون استفاده از این خاصیت، در صورت استفاده از خاصیت clickable، هنگام لمس دکمه، همان رنگ پس زمینه دکمه قدری تیره تر می شود اما با استفاده از rippleColor و تعریف یک رنگ جدید، ripple Animation لمس دکمه با این رنگ اجرا خواهد شد:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;android.support.design.widget.FloatingActionButton
    android:id=&quot;@+id/fab&quot;
    android:layout_width=&quot;wrap_content&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:layout_gravity=&quot;bottom|start&quot;
    android:layout_margin=&quot;16dp&quot;
    android:src=&quot;@android:drawable/ic_dialog_email&quot;
    app:backgroundTint=&quot;#2c489c&quot;
    android:clickable=&quot;true&quot;
    android:focusable=&quot;true&quot;
    app:fabSize=&quot;normal&quot;
    app:rippleColor=&quot;#b12f2f&quot;/&gt;
</pre>
<p>(جهت مشاهده واضح تر نتیجه روی اسکرین شات، سایز دکمه را مجدد به نرمال تغییر دادم.)</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/fab/add_rippleColor_attribute_to_fab.png" alt="تغییر رنگ rippleAnimation دکمه شناور اندروید با استفاده از rippleColor" /></p>
<p>مرحله نهایی تعریف یک رویداد برای دکمه شناور است که مانند سایر دکمه هاست:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.fab;

import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    FloatingActionButton mFab;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mFab = findViewById(R.id.fab);

        mFab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                Toast.makeText( MainActivity.this, &quot;FAB Clicked&quot;, Toast.LENGTH_SHORT).show();

            }
        });

    }
}
</pre>
<p>به خط زیر دقت کنید:</p>
<pre class="brush: java; title: ; notranslate">
mFab = findViewById(R.id.fab);
</pre>
<p>قبلا لازم بود عمل Casting را هنگام تعریف یک view در جاوا انجام دهیم. مانند زیر:</p>
<pre class="brush: java; title: ; notranslate">
mFab = (FloatingActionButton) findViewById(R.id.fab);
</pre>
<p>اما در نسخه جدید اندروید استودیو این عمل ضروری نیست و در صورت استفاده، پیغامی مبنی بر زائد و اضافی بودن Casting نشان می دهد.<br />
حالا پروژه را اجرا و روی FloatingActionButton کلیک می کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/fab/fab_onClick_event.png" alt="تعریف رویداد onClick برای دکمه شناور FAB" /></p>
<p>پیغام Toast به درستی اجرا شد.</p>
<p><span class="notice">توجه :</span> سورس پروژه درون پوشه Exercises قرار داده شده است</p>
<div class="alert dlbox">
<span class="title"><i class="titleicon fa fa-download fa-lg"></i>دانلود فایل این آموزش با فرمت PDF به همراه سورس پروژه</span><br />
<i class="dlicon fa fa-square fa-lg"></i> تعداد صفحات : ۱۰<br />
<i class="dlicon fa fa-square fa-lg"></i> حجم : ۱ مگابایت<br />
<i class="dlicon fa fa-square fa-lg"></i> قیمت : رایگان<br />
<a href="http://dl.android-studio.ir/courses/9_5_floating_action_button.zip" class="button green edd-submit">دانلود رایگان با حجم ۱ مگابایت</a> <a href="http://dl2.android-studio.ir/courses/9_5_floating_action_button.zip" class="button red edd-submit">لینک کمکی</a>
</div>
<p>نوشته <a href="https://android-studio.ir/android-floating-action-button/">دکمه شناور یا Floating Action Button متریال دیزاین</a> اولین بار در <a href="https://android-studio.ir">اندروید استودیو</a> پدیدار شد.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://android-studio.ir/android-floating-action-button/feed/</wfw:commentRss>
			<slash:comments>16</slash:comments>
		
		
			</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

ذخیره سازی صفحه با استفاده از Disk: Enhanced 
بارگذاری تنبل (feed)

Served from: android-studio.ir @ 2026-07-11 01:58:25 by W3 Total Cache
-->