<?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/%D8%B1%D8%A7%D8%A8%D8%B7_%DA%A9%D8%A7%D8%B1%D8%A8%D8%B1%DB%8C/feed/" rel="self" type="application/rss+xml" />
	<link>https://android-studio.ir/tag/رابط_کاربری/</link>
	<description>آموزش برنامه نویسی اندروید</description>
	<lastBuildDate>Thu, 13 Apr 2023 12:30:43 +0000</lastBuildDate>
	<language>fa-IR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	
	<item>
		<title>ویژگی‌ها و استایل‌های مختلف نوتیفیکیشن در اندروید</title>
		<link>https://android-studio.ir/advanced-android-notifications/</link>
					<comments>https://android-studio.ir/advanced-android-notifications/#comments</comments>
		
		<dc:creator><![CDATA[سیدمهدی مطهری]]></dc:creator>
		<pubDate>Thu, 04 Jul 2019 11:07:49 +0000</pubDate>
				<category><![CDATA[آموزش‌های پایه]]></category>
		<category><![CDATA[رابط_کاربری]]></category>
		<category><![CDATA[رابط_کاربری_اندروید]]></category>
		<guid isPermaLink="false">https://android-studio.ir/?p=159502</guid>

					<description><![CDATA[<p>در این قسمت از سری مباحث آموزش برنامه نویسی اندروید به نحوه ساخت انواع نوتیفیکیشن یا اعلان در اندروید پرداخته و طریقه پیاده سازی استایل‌های مختلف و ویژگی‌ها و امکانات متنوعی که برای نوتیفیکیشن معرفی شده را بررسی و تمرین می‌کنیم. آنچه در این آموزش می‌خوانید: آشنایی با ساختار نوتیفیکیشن (Notification) در سیستم عامل اندروید [&#8230;]</p>
<p>نوشته <a href="https://android-studio.ir/advanced-android-notifications/">ویژگی‌ها و استایل‌های مختلف نوتیفیکیشن در اندروید</a> اولین بار در <a href="https://android-studio.ir">اندروید استودیو</a> پدیدار شد.</p>
]]></description>
										<content:encoded><![CDATA[<p>در این قسمت از سری مباحث <a href="http://android-studio.ir/" target="_blank" rel="noopener noreferrer">آموزش برنامه نویسی اندروید</a> به نحوه ساخت انواع نوتیفیکیشن یا اعلان در اندروید پرداخته و طریقه پیاده سازی استایل‌های مختلف و ویژگی‌ها و امکانات متنوعی که برای نوتیفیکیشن معرفی شده را بررسی و تمرین می‌کنیم.</p>
<div class="title-box">
<b>آنچه در این آموزش می‌خوانید:</b></p>
<ul>
<li>آشنایی با ساختار نوتیفیکیشن (Notification) در سیستم عامل اندروید</li>
<li>معرفی متد PendingIntent جهت تعامل کاربر با نوتیفیکیشن‌ها و هدایت وی به مقصد موردنظر</li>
<li>کار با دکمه‌های Action در نوتیفیکیشن</li>
<li>تفاوت نحوه نمایش اکشن‌ها در نسخه‌های قدیم و جدید اندروید</li>
<li>نمایش متن طولانی در اعلان به وسیله استایل BigTextStyle و گنجاندن خلاصه متن در نوتیفیکیشن</li>
<li>معرفی نوتیفیکیشن‌هایی که باز و بسته می‌شوند (Expandable Notification)</li>
<li>نمایش تصویر بزرگ در Notification با استفاده از استایل BigPictureStyle</li>
<li>نحوه تبدیل تصاویر با فرمت JPG و PNG به Bitmap در اندروید</li>
<li>نمایش لیست پیغام‌های دریافتی توسط InboxStyle</li>
<li>حذف و یا لغو نوتیفیکیشن پس از انجام یک عمل خاص و یا بصورت خودکار و پس از گذشت زمان مشخص</li>
<li>مدیریت Notification Badge از قبیل نحوه نمایش اعلان‌ها و همچنین تعداد پیغام‌های دریافتی</li>
<li>نحوه غیر فعال کردن Notification Badge یا Notification Dots</li>
<li>حذف یک Notification Channel از روی سیستم عامل اندروید توسط deleteNotificationChannel</li>
</ul>
</div>
<p class="copy">این مبحث در قالب PDF و در ۲۷ صفحه تهیه شده که در ادامه چند صفحه‌ی ابتدایی را مشاهده می‌کنید:</p>
<p></p>
<p>در قسمت قبل با نحوه <a href="http://android-studio.ir/android-notification/" target="_blank" rel="noopener noreferrer">ساخت نوتیفیکیشن در اندروید</a> آشنا شدیم. در این مبحث قصد دارم انواع نوتیفیکیشن، حالت‌ها و امکانات مختلف قابل پیاده سازی برای اعلان‌های اندرویدی را معرفی کنم.<br />
برای این قسمت پروژه جدیدی نمی‌سازم و از همان پروژه قسمت قبل استفاده می‌کنم.</p>
<h2>ساختار نوتیفیکیشن اندروید</h2>
<p>به نام خدا. قبل از ادامه مبحث ابتدا بهتر است ساختار نوتیفیکیشنی که در مبحث قبل ساختیم را مرور کنیم. هرکدام از اجزاء اعلان را به ترتیب شماره توضیح می‌دهم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/notifstyles/android_notification_parts.png" alt="ساختار نوتیفیکیشن Notification در اندروید" /></p>
<p>۱: آیکون کوچک (Small icon): این آیکون توسط setSmallIcon ساخته شده که تعریف آن برای نوتیفیکیشن الزامی است.<br />
۲: در اینجا نام اپلیکیشنی که نوتیفیکیشن را اجرا کرده نمایش داده می‌شود.<br />
۳: زمان ساخت نوتیفیکیشن را نشان می‌دهد. البته می‌توان این قسمت را به دلخواه تغییر داد و یا حذف کرد.<br />
۴: آیکون بزرگ (Large icon): این آیکون توسط setLargeIcon ساخته شده و کاربرد آن نمایش یک آیکون یا تصویر بزرگ در کنار پیغام است.<br />
۵: عنوان نوتیفیکیشن<br />
۶: متن نوتیفیکیشن</p>
<h2>انواع نوتیفیکیشن در اندروید</h2>
<p>اعلان‌ها یا همان Notification را به روش‌های مختلفی می‌توان پیاده سازی کرد که هرکدام کاربرد مختص خود را داراست. یک نوتیفیکیشن صرفا پیام مختصری را به کاربر اطلاع می‌دهد. دیگری جزئیات بیشتری در اختیار کاربر قرار داده و او را به سمت یک اکتیویتی در اپلیکیشن و یا یک صفحه وب هدایت می‌کند. و انواع دیگری از نحوه ساخت و اجرای نوتیفیکیشن وجود دارد که در اینجا تعدادی را بررسی می‌کنیم.</p>
<div class="alert alert-warning">
<span class="notice">نکته:</span> کد کامل اکتیویتی علاوه بر سورس پروژه، در انتهای همین آموزش نیز قید شده. بنابراین در هر مرحله اگر با ابهامی مواجه شدید به کد کامل مراجعه کنید. به جهت خلاصه شدن متن، از توضیحات تکراری (شامل ساخت دکمه، تعریف آن در کلاس اکتیویتی، ساخت متد setOnClickListener و&#8230;) تا حد امکان اجتناب کردم.
</div>
<div class="alert alert-warning">
<span class="notice">نکته:</span> پیاده سازی قواعد و اصول طراحی متریال در نوتیفیکیشن‌ها از اهمیت بالایی برخوردار است. منابعی مانند <a href="https://material.io/design/platform-guidance/android-notifications.html" target="_blank" rel="noopener noreferrer">این لینک</a> کمک زیادی در درک بهتر جزئیات طراحی به ما می‌کند.
</div>
<h3>استفاده از PendingIntent و ساخت Action برای نوتیفیکیشن</h3>
<p>نوتیفیکیشنی که قبلا ساختیم صرفا یک پیغام را به کاربر نمایش می‌دهد و غیر از بستن آن، کاربر هیچگونه تعاملی نمی‌تواند با این پیغام داشته باشد. در صورتی که ما به این تعامل نیاز داریم. اگر اعلان مربوط به یک تخفیف است، می‌بایست کاربر را به صفحه مرتبط با آن هدایت کند. در اینجا از pendingIntent استفاده می‌کنیم. قبلا با نحوه <a href="http://android-studio.ir/intent/" target="_blank" rel="noopener noreferrer">کار با intent در اندروید</a> آشنا شدیم. حالا در نوتیفیکیشن هم با استفاده از اینتنت تعیین می‌کنیم بعد از لمس اعلان توسط کاربر، چه عملی صورت پذیرد.<br />
پروژه Notification را باز می‌کنم. ابتدا یک دکمه با عنوان PendingIntent Notification به Layout اکتیویتی اضافه می‌کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/notifstyles/add_pendingIntent_button_to_layout.png" alt="ساخت نوتیفیکیشن در اندروید توسط PendingIntent" /></p>
<p>سپس طبق کد زیر یک نوتیفیکیشن دیگر داخل اکتیویتی می‌سازم:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.notification;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.NotificationCompat;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.media.RingtoneManager;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    Button simpleButton, pendingButton;
    NotificationManager notifManager;
    String offerChannelId = &quot;Offers&quot;;
    PendingIntent mpIntent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        simpleButton = findViewById(R.id.simple_notif);
        pendingButton = findViewById(R.id.pending_notif);

        notifManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        Intent pIntent = new Intent(this, CartActivity.class);
        mpIntent = PendingIntent.getActivity(this, 0, pIntent, PendingIntent.FLAG_UPDATE_CURRENT);

        simpleButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                createNotifChannel();
                simpleNotification();

            }
        });

        pendingButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                createNotifChannel();
                pendingNotification();

            }
        });

    }

    private void createNotifChannel() {

        if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.O) {

            String offerChannelName = &quot;Shop offers&quot;;
            String offerChannelDescription= &quot;Best offers for customers&quot;;
            int offerChannelImportance = NotificationManager.IMPORTANCE_DEFAULT;

            NotificationChannel notifChannel = new NotificationChannel(offerChannelId, offerChannelName, offerChannelImportance);
            notifChannel.setDescription(offerChannelDescription);
            //notifChannel.enableVibration(true);
            notifChannel.enableLights(true);
            notifChannel.setLightColor(Color.GREEN);

            notifManager.createNotificationChannel(notifChannel);

        }

    }

    public void simpleNotification() {

        NotificationCompat.Builder sNotifBuilder = new NotificationCompat.Builder(this, offerChannelId)
                .setSmallIcon(R.drawable.notif_icon)
                .setContentTitle(&quot;بروزرسانی&quot;)
                .setContentText(&quot;یک نسخه جدید از برنامه آماده دریافت است&quot;)
                .setVibrate(new long&#x5B;]{100,500,500,500,500,500})
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.android))
                .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
                .setVisibility(NotificationCompat.VISIBILITY_PUBLIC);

        notifManager.notify(1, sNotifBuilder.build());

    }

    public void pendingNotification() {

        NotificationCompat.Builder pNotifBuilder = new NotificationCompat.Builder(this, offerChannelId)
                .setSmallIcon(R.drawable.notif_icon)
                .setContentTitle(&quot;تخفیف پنجاه درصدی!&quot;)
                .setContentText(&quot;پنجاه درصد تخفیف به مناسبت طلوع خورشید&quot;)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.android))
                .setContentIntent(mpIntent);

        notifManager.notify(2, pNotifBuilder.build());

    }

}
</pre>
<p>در کد فوق ابتدا pendingButton را به دکمه مربوطه در لِی اوت متصل کردم. سپس یک شیء از Intent با نام mIntent ساختم:</p>
<pre class="brush: java; title: ; notranslate">
Intent pIntent = new Intent(this, CartActivity.class);
</pre>
<p>به جهت ملموس بودن نتیجه کار، یک اکتیویتی با نام CartActivity به پروژه اضافه کرده و به اینتنت معرفی کردم.</p>
<pre class="brush: java; title: ; notranslate">
mpIntent = PendingIntent.getActivity(this, 0, pIntent, PendingIntent.FLAG_UPDATE_CURRENT);
</pre>
<p>سپس با استفاده از متد PendingIntent و getActivity تعیین می‌کنم با لمس نوتیفیکیشن، pIntent اجرا شود. این متد ۴ پارامتر می‌گیرد که در جدول زیر معرفی شده:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/notifstyles/pendingIntent_parameters.png" alt="پارامترهای ورودی pendingIntent" /></p>
<p>اولی Context است که this وارد کردم. پارامتر دوم یک مقدار از جنس int است که به عنوان یک کد درخواست خصوصی تلقی می‌شود. من برای این نوتیفیکیشن مقدار ۰ قرار دادم. پارامتر سوم اینتنتی است که قبلا تعریف کردم یعنی pIntent. آخرین پارامتر یعنی flags جهت تعیین وضعیت اینتنت است که من در اینجا از نوع FLAG_UPDATE_CURRENT انتخاب کردم.<br />
در قدم بعد یک تابع با نام pendingNotification به کلاس اضافه کردم. ۴ متد نخست این تابع مشابه simpleNotification است که در مبحث قبل توضیحات لازم ارائه شده.</p>
<pre class="brush: java; title: ; notranslate">
public void pendingNotification() {

    NotificationCompat.Builder pNotifBuilder = new NotificationCompat.Builder(this, offerChannelId)
            .setSmallIcon(R.drawable.notif_icon)
            .setContentTitle(&quot;تخفیف پنجاه درصدی!&quot;)
            .setContentText(&quot;پنجاه درصد تخفیف به مناسبت طلوع خورشید&quot;)
            .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.android))
            .setContentIntent(mpIntent); 

    notifManager.notify(2, pNotifBuilder.build());

}
</pre>
<p>توسط setContentIntent اینتنتی که قبلا ساختم را به نوتیفیکیشن معرفی می‌کنم.<br />
در نهایت متد setOnClickListener مربوط به دکمه pendingButton را ساخته و توابع مرتبط با کانال و نوتیفیکیشن را فراخوانی می‌کنم. (برای سایر نوتیفیکیشن‌ها نیز همین مراحل تکرار می‌شود؛ یعنی اضافه کردن دکمه در Layout، ساخت متد setOnClickListener و فراخوانی توابع کانال و نوتیفیکیشن مربوط به آن درون این متد).<br />
پروژه را اجرا کرده و روی دکمه PendingIntent Notification کلیک می‌کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/notifstyles/click_on_pendingIntent_notification.png" alt="اجرای نوتیفیکیشن در اندروید" /></p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/notifstyles/notification_not_removed_after_click.png" alt="حذف نوتیفیکیشن بعد از کلیک روی آن" /></p>
<p>با کلیک روی نوتیفیکیشن، به اکتیویتی CartActivity هدایت شدم. اما یک ایراد وجود دارد. به نوار وضعیت تصویر دوم دقت کنید. هنوز آیکون نوتیفیکیشن مشاهده می‌شود. یعنی با وجود اینکه کاربر روی نوتیفیکیشن کلیک کرده و به مقصد مدنظر منتقل شده، اعلان همچنان باقی مانده که لازم است این مشکل را رفع کنیم. اینکار توسط متد setAutoCancel انجام می‌پذیرد:</p>
<pre class="brush: java; title: ; notranslate">
NotificationCompat.Builder pNotifBuilder = new NotificationCompat.Builder(this, offerChannelId)
        .setSmallIcon(R.drawable.notif_icon)
        .setContentTitle(&quot;تخفیف پنجاه درصدی!&quot;)
        .setContentText(&quot;پنجاه درصد تخفیف به مناسبت طلوع خورشید&quot;)
        .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.android))
        .setContentIntent(mpIntent)
        .setAutoCancel(true);
</pre>
<p>با اجرای مجدد پروژه، بعد از کلیک روی Notification، علاوه بر انتقال کاربر به صفحه CartActivity نوتیفیکیشن نیز حذف می‌شود.<br />
علاوه بر کلیک روی نوتیفیکیشن، می‌توان دکمه‌هایی به اعلان افزود که برای هرکدام نیز یک intent مجزا تعریف شده باشد. این دکمه‌ها یک Action می‌نامیم.<br />
برای مثال، نوتیفیکیشن برنامه مدیریت پیامک عموما دو گزینه دارد. اولی Reply جهت پاسخ دادن به پیامک دریافتی و دومی Mark as read که با لمس این دکمه، پیامک از حالت &#8220;خوانده نشده&#8221; به &#8220;خوانده شده&#8221; تغییر وضعیت پیدا می‌کند.<br />
من متد setContentIntent را غیرفعال کرده و بجای آن دو Action به نوتیفیکیشن اضافه می‌کنم:</p>
<pre class="brush: java; title: ; notranslate">
NotificationCompat.Builder pNotifBuilder = new NotificationCompat.Builder(this, offerChannelId)
        .setSmallIcon(R.drawable.notif_icon)
        .setContentTitle(&quot;تخفیف پنجاه درصدی!&quot;)
        .setContentText(&quot;پنجاه درصد تخفیف به مناسبت طلوع خورشید&quot;)
        .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.android))
        //.setContentIntent(mpIntent)
        .addAction(R.drawable.notif_icon, &quot;Buy&quot;, mpIntent)
        .addAction(R.drawable.notif_icon, &quot;Product details&quot;, mpIntent)
        .setAutoCancel(true);
</pre>
<p>addAction سه ورودی می‌گیرد:<br />
<b>ورودی اول:</b> برای هر گزینه می‌توان یک آیکون تعریف کرد. البته توجه داشته باشید از اندروید Nougat به بعد برای سادگی بیشتر محیط نوتیفیکیشن، این آیکون‌ها نمایش داده نمی‌شوند.<br />
<b>ورودی دوم:</b> عنوان اکشن است که برای اکشن اول &#8220;Buy&#8221; و اکشن دوم &#8220;Product details&#8221; وارد کردم.<br />
<b>ورودی سوم:</b> PendingIntent ای که قبلا تعریف شده. </p>
<p>مجدد پروژه را اجرا می‌کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/notifstyles/notification_addAction_method.png" alt="اضافه کردن دکمه Action به نوتیفیکیشن اندروید توسط متد addAction" /></p>
<p>دو اکشن به انتهای نوتیفیکیشن اضافه شده که البته در این مثال هردو یک عملکرد دارند؛ یعنی هدایت به CartActivity.<br />
همانطور که قبلا اشاره کردم، از اندروید N و به بالاتر، آیکون گزینه‌ها نمایش داده نمی‌شود. اما روی دیوایس‌های پایین‌تر از این نسخه، آیکون‌ها در کنار عنوان دکمه وجود دارد. پروژه را روی یک دیوایس با API 23 اجرا کردم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/notifstyles/addAction_icon_in_android_lower_N.png" alt="عدم نمایش آیکون اکشن نوتیفیکیشن در اندروید پایینتر از N" /></p>
<div class="alert alert-warning">
<span class="notice">نکته:</span> با کلیک روی اکشن‌ها کاربر به مقصد هدایت شده اما بازهم نوتیفیکیشن حذف نمی‌شود. یعنی setAutoCancel اینجا کاربردی ندارد. برای حل این مشکل از متد cancel استفاده می‌شود که در صفحه ۱۸ به آن پرداخته شده است.
</div>
<h3>نمایش متن بزرگ در نوتیفیکیشن توسط BigTextStyle</h3>
<p>گاهی اوقات لازم است متن طولانی تری در نوتیفیکیشن به کاربر نمایش دهیم. اگر برای متن طولانی از setContentText استفاده کنیم تنها چند کلمه ابتدای آن قابل مشاهده خواهد بود. اینجاست که استایل‌ها در نوتیفیکیشن امکان شخصی سازی بیشتری به ما می‌دهند. به کد زیر دقت کنید:</p>
<pre class="brush: java; title: ; notranslate">
public void bigTextNotification() {

    NotificationCompat.BigTextStyle bStyle = new NotificationCompat.BigTextStyle()
            .bigText(&quot;لورم ایپسوم متنی است که ساختگی برای طراحی و چاپ آن مورد است. صنعت چاپ زمانی لازم بود شرایطی شما باید فکر ثبت نام و طراحی، لازمه خروج می باشد &quot;)
            .setBigContentTitle(&quot;نوتیفیکیشن طولانی&quot;)
            .setSummaryText(&quot;خلاصه متن طولانی&quot;);

    NotificationCompat.Builder bNotifBuilder = new NotificationCompat.Builder(this, offerChannelId)
            .setSmallIcon(R.drawable.notif_icon)
            .setContentTitle(&quot;تخفیف پنجاه درصدی! &quot;)
            .setContentText(&quot;پنجاه درصد تخفیف به مناسبت طلوع خورشید&quot;)
            .setStyle(bStyle);

    notifManager.notify(3, bNotifBuilder.build());

}
</pre>
<p>مانند قبل یک تابع جدید به کلاس اضافه کردم. نام این تابع را bigTextNotification گذاشتم.<br />
در NotificationCompat امکان تعریف Style ها را داریم. در اینجا من از BigTextStyle یک شیء با نام bStyle ایجاد کرده‌ام که ۳ ویژگی برای آن تعریف شده.</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=159503" 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/advanced-android-notifications/">ویژگی‌ها و استایل‌های مختلف نوتیفیکیشن در اندروید</a> اولین بار در <a href="https://android-studio.ir">اندروید استودیو</a> پدیدار شد.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://android-studio.ir/advanced-android-notifications/feed/</wfw:commentRss>
			<slash:comments>6</slash:comments>
		
		
			</item>
		<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>نمایش اعداد فارسی در View های اندروید</title>
		<link>https://android-studio.ir/farsi-numbers-in-android-programming/</link>
					<comments>https://android-studio.ir/farsi-numbers-in-android-programming/#comments</comments>
		
		<dc:creator><![CDATA[سیدمهدی مطهری]]></dc:creator>
		<pubDate>Mon, 22 Apr 2019 11:22:08 +0000</pubDate>
				<category><![CDATA[آموزش‌های تکمیلی]]></category>
		<category><![CDATA[آموزش‌های رایگان]]></category>
		<category><![CDATA[رابط_کاربری]]></category>
		<category><![CDATA[رابط_کاربری_اندروید]]></category>
		<guid isPermaLink="false">https://android-studio.ir/?p=156188</guid>

					<description><![CDATA[<p>به نام خدا. در این مبحث ابتدا روش‌های متفاوت نمایش اعداد فارسی در برنامه‌ی اندرویدی را بررسی کرده سپس یک متد جاوا برای تبدیل اعداد انگلیسی به فارسی می‌نویسیم و در View های پروژه اندروید برای نمایش اعداد به صورت فارسی از آن استفاده می‌کنیم. آنچه در این آموزش می‌خوانید: چرا باید از اعداد فارسی [&#8230;]</p>
<p>نوشته <a href="https://android-studio.ir/farsi-numbers-in-android-programming/">نمایش اعداد فارسی در View های اندروید</a> اولین بار در <a href="https://android-studio.ir">اندروید استودیو</a> پدیدار شد.</p>
]]></description>
										<content:encoded><![CDATA[<p>به نام خدا. در این مبحث ابتدا روش‌های متفاوت <a href="http://android-studio.ir/farsi-numbers-in-android-programming/">نمایش اعداد فارسی در برنامه‌ی اندرویدی</a> را بررسی کرده سپس یک متد جاوا برای تبدیل اعداد انگلیسی به فارسی می‌نویسیم و در View های <a href="http://android-studio.ir/create-android-project-and-its-structure/">پروژه اندروید</a> برای نمایش اعداد به صورت فارسی از آن استفاده می‌کنیم.</p>
<div class="title-box">
<b>آنچه در این آموزش می‌خوانید:</b></p>
<ul>
<li><a href="#benefits-of-using-farsi-numbers-in-android-apps">چرا باید از اعداد فارسی در برنامه اندروید استفاده کنیم؟</a></li>
<li><a href="#methods-of-display-farsi-numbers-in-android-applications">روش‌های نمایش اعداد فارسی در اپلیکیشن اندروید</a></li>
<li><a href="#change-english-numbers-to-farsi-in-android-views">تبدیل اعداد انگلیسی به فارسی در View های اندروید</a></li>
</ul>
</div>
<h2 id="benefits-of-using-farsi-numbers-in-android-apps">چرا باید از اعداد فارسی در برنامه اندروید استفاده کنیم؟</h2>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/fanum/show_farsi_numbers_in_android_application.png" alt="نمایش اعداد فارسی در برنامه نویسی اندروید" /></p>
<p>یکی از مشکلات توسعه دهندگان فارسی زبان، نمایش اعداد انگلیسی در محیط اپلیکیشن اندرویدی است که باعث ایجاد نوعی بی‌نظمی در <a href="http://android-studio.ir/android-user-interface/">رابط کاربری برنامه اندرویدی</a> می‌شود. یک متن فارسی که در میان آن چند عدد قرار گرفته و همه آنها با فرمت اعداد انگلیسی نمایش داده می‌شوند. یا به عنوان مثال قیمت یک محصول در اپلیکیشن فروشگاهی شما به‌اینصورت به مخاطب نشان داده شود: </p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/fanum/change_english_to_farsi_numbers.png" alt="تبدیل عدد انگلیسی به فارسی در پروژه ی اندرویدی" /></p>
<p>این یک امتیاز منفی برای اپلیکیشن به حساب می‌آید. درست همانطور که نمایش عددهای فارسی در یک متن انگلیسی می‌تواند مضحک بنظر برسد!<br />
بنابراین لازم است در صفحاتِ با محتوای فارسی حتما از اعداد فارسی استفاده کنیم (مگر در موارد خاص). در اینصورت خوانایی محتوا نیز برای کاربر بهینه می‌شود.</p>
<h2 id="methods-of-display-farsi-numbers-in-android-applications">روش‌های نمایش اعداد فارسی در اپلیکیشن اندروید</h2>
<p>برای نمایش عددهای فارسی در <a href="http://android-studio.ir/">برنامه نویسی اندروید</a>، راهکارهای متفاوتی وجود دارد که در اینجا به چند مورد اشاره می‌کنم:<br />
<b>۱- بکاربردن مستقیم اعداد فارسی در متن و قسمت‌های مدنظر:</b> در این حالت کافیست اعداد به صورت فارسی به View ها ارسال شوند. چه محتوایی که در دیتابیس ذخیره شده چه آنهایی که به واسطه <a href="http://android-studio.ir/retrofit-with-php-mysql-web-service/">وب سرویس</a> از سرور دریافت می‌شوند و چه آنهایی که در خود اکتیویتی‌ و Layout قرار گرفته اند.<br />
<b>۲- استفاده از فونت‌های فارسی:</b> اگر مبحث <a href="http://android-studio.ir/set-custom-fonts-on-android-applications/">تغییر فونت در برنامه اندرویدی</a> را مطالعه کرده باشید، روش‌های متفاوت تغییر فونت پیش فرض اندروید را بررسی کردیم. برخی فونت‌های فارسی، اعداد انگلیسی را هم به صورت فارسی نمایش می‌دهند بنابراین خیلی ساده و بدون نیاز به هیچ عمل دیگری می‌توانید مسئله را حل کنید. به عنوان مثال فونت IRANSans برای اپلیکیشن‌های موبایلی دو فونت متفاوت ارائه داده که در یکی از آنها فارغ از اینکه اعداد فارسی یا انگلیسی هستند، آنها را به صورت فارسی نمایش می‌دهد. البته استفاده از این نوع فونت یک ایراد دارد که در واقع همان ویژگی آن محسوب می‌شود! یعنی شما امکان نمایش اعداد انگلیسی را نخواهید داشت. فرض کنید نام و مدل یک محصول در فروشگاه شما LG G7 است. طبیعتا چون نام و مدل، کاراکترهای انگلیسی هستند، عدد بکار رفته در سری یا مدل این محصول نیز باید انگلیسی باشد نه فارسی. مگر آنکه هر دو فونت استاندارد و به اصطلاح FaNum را در پروژه بکار ببریم و در هر View بنا به نیاز از یکی از آنها استفاده کنیم.<br />
<b>۳- تبدیل اعداد انگلیسی به فارسی:</b> در این روش باید متدی را پیاده سازی کنیم که قبل از ارسال محتوا به View مدنظر، چک کند اگر عدد یا اعداد انگلیسی وجود دارد آنها را با اعداد فارسی جایگزین نماید. در این مبحث قصد دارم این روش را آموزش دهم.</p>
<h2 id="change-english-numbers-to-farsi-in-android-views">تبدیل اعداد انگلیسی به فارسی در View های اندروید</h2>
<p>در این روش یک متد می‌سازیم که محتوای ارسالی به View را بررسی می‌کند و درصورت وجود اعداد انگلیسی، آنها را به اعداد فارسی تبدیل می‌کند.<br />
ابتدا یک پروژه با نام FarsiNumbers در اندروید استودیو می‌سازم که اکتیویتی آن از نوع Empty Activity است.</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/fanum/farsi_numbers_android_project_in_android_studio.png" alt="تبدیل اعداد انگلیسی به فارسی در برنامه اندرویدی" /></p>
<p>پروژه با موفقیت بیلد شد. حالا یک کلاس جاوا به پروژه اضافه می‌کنم. من نام این کلاس را FaNum انتخاب کردم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/fanum/add_FaNum_class_to_android_project.png" alt="نمایش اعداد فارسی در پروژه اندروید در اندروید استودیو" /></p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/fanum/add_FaNum_class_to_android_project_2.png" alt="نمایش اعداد فارسی در View و TextView اندروید" /></p>
<p>کلاس FaNum.java را بصورت زیر تکمیل می‌کنم:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.farsinumbers;

public class FaNum {

    public static String convert(String faNumbers) {
        String&#x5B;]&#x5B;] mChars = new String&#x5B;]&#x5B;]{
                {&quot;0&quot;, &quot;۰&quot;},
                {&quot;1&quot;, &quot;۱&quot;},
                {&quot;2&quot;, &quot;۲&quot;},
                {&quot;3&quot;, &quot;۳&quot;},
                {&quot;4&quot;, &quot;۴&quot;},
                {&quot;5&quot;, &quot;۵&quot;},
                {&quot;6&quot;, &quot;۶&quot;},
                {&quot;7&quot;, &quot;۷&quot;},
                {&quot;8&quot;, &quot;۸&quot;},
                {&quot;9&quot;, &quot;۹&quot;}
        };

        for (String&#x5B;] num : mChars) {

            faNumbers = faNumbers.replace(num&#x5B;0], num&#x5B;1]);

        }

        return faNumbers;
    }

}
</pre>
<p>یک متد از نوع String و با نام دلخواه convert درون کلاس ایجاد کردم که پارامتر ورودی آن از نوع String و با نام دلخواه faNumbers انتخاب شده. در ادامه یک آرایه دو بُعدی با نام mChars ساخته‌ام که مقادیر آن شامل اعداد انگلیسی و فارسی‌ست. ستون اول (اندیس صفر) مربوط به اعداد انگلیسی و ستون دوم (اندیس یک) مربوط به اعداد فارسی می‌باشد. سپس یک for تعریف شده. درون بلاک for از متد replace استفاده شده به‌اینصورت که کاراکترهای دریافتی بررسی شده و در صورت وجود کاراکتر (اعداد) انگلیسی (ستون اول)، با عدد فارسی مقابل آن (ستون دوم) تعویض و جایگذاری می‌شود. به عبارتی اندیس ۱ جایگزین اندیس ۰ می‌شود.<br />
در نهایت چون متد از نوع بازگشتی است، مقدار خروجی return می‌شود.<br />
متد کامل شد. حالا برای تست متدی که ساختم، یک TextView به اکتیویتی اضافه می‌کنم:</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;TextView
        android:layout_width=&quot;wrap_content&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:id=&quot;@+id/m_txt&quot;
        android:layout_centerInParent=&quot;true&quot;
        android:textSize=&quot;40sp&quot;/&gt;

&lt;/RelativeLayout&gt;
</pre>
<p>MainActivity.java:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.farsinumbers;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView mText = findViewById(R.id.m_txt);

        mText.setText(&quot;1234567890&quot;);

    }
}
</pre>
<p>ابتدا توسط متد setText یک رشته شامل اعداد ۰ تا ۹ انگلیسی را به TextView ارسال می‌کنم. با اجرای پروژه روی <a href="http://android-studio.ir/install-genymotion/">شبیه ساز اندروید</a> مسلما اعداد به صورت انگلیسی ظاهر خواهند شد:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/fanum/show_numbers_using_settext_method.png" alt="نمایش اعداد فارسی توسط متد setText در اندروید استودیو" /></p>
<p>حالا از متدی که نوشتم استفاده می‌کنم و انتظار دارم با افزودن متد convert کلاس FaNum به setText اعداد به صورت فارسی نمایش داده شوند:</p>
<pre class="brush: java; title: ; notranslate">
mText.setText(FaNum.convert(&quot;1234567890&quot;));
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/fanum/show_farsi_numbers_using_convert_method.png" alt="تبدیل اعداد انگلیسی به فارسی توسط متد جاوا در اندروید" /></p>
<p>متد به درستی کار می‌کند. </p>
<p>این متد را به صورت‌های دیگری نیز می‌توان پیاده سازی کرد که با جستجو در وب به نمونه‌هایی برخورد می‌کنیم. یکی از آنها را در اینجا ذکر می‌کنم:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.farsinumbers;

public class FaNum2 {

    private static String&#x5B;] faNumbers = new String&#x5B;]{&quot;۰&quot;,&quot;۱&quot;,&quot;۲&quot;,&quot;۳&quot;,&quot;۴&quot;,&quot;۵&quot;,&quot;۶&quot;,&quot;۷&quot;,&quot;۸&quot;,&quot;۹&quot;};

    public static String convert(String text) {
        if (text.length() == 0) {
            return &quot;&quot;;
        }
        String out = &quot;&quot;;
        int length = text.length();
        for (int i = 0; i &lt; length; i++) {
            char c = text.charAt(i);
            if ('0' &lt;= c &amp;&amp; c &lt;= '9') {
                int number = Integer.parseInt(String.valueOf(c));
                out += faNumbers&#x5B;number];
            } else if (c == '٫' || c == ',') {
                out += '،';
            } else {
                out += c;
            }
        }
        return out;
    }

}
</pre>
<p>یک کلاس جدید با نام FaNum2 به پروژه اضافه کرده و متد فوق را درون آن قرار دادم. حالا کافیست در setText متد convert این کلاس را فراخوانی کنم:</p>
<pre class="brush: java; title: ; notranslate">
mText.setText(FaNum2.convert(&quot;1234567890&quot;));
</pre>
<p>نتیجه مشابه خروجی متد قبل بوده و اعداد فارسی نمایش داده می‌شوند.<br />
به تکه کد زیر دقت کنید:</p>
<pre class="brush: java; title: ; notranslate">
if (c == '٫' || c == ',') {
    out += '،';
}
</pre>
<p>کاربرد این کد برای مواقعی است که قیمت محصولات دارای جداکننده باشد و بخواهیم کاراکتر جداکننده نیز به ویرگول فارسی تبدیل شود.<br />
اعداد را توسط جداکننده (ویرگول انگلیسی) به صورت سه رقم از یکدیگر جدا کرده و مجدد پروژه را اجرا می‌کنم:</p>
<pre class="brush: java; title: ; notranslate">
mText.setText(FaNum2.convert(&quot;123,4567,890&quot;));
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/fanum/show_farsi_semicolon_in_android_application.png" alt="نمایش ویرگول فارسی در View های اندروید" /></p>
<p>خروجی همان چیزی است که انتظارش را داشتیم.</p>
<p class="source">توجه: سورس پروژه درون پوشه 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/FarsiNumber.zip" class="button green edd-submit">دانلود رایگان با حجم ۱ مگابایت</a> <a href="http://dl2.android-studio.ir/courses/FarsiNumber.zip" class="button red edd-submit">لینک کمکی</a>
</div>
<p>نوشته <a href="https://android-studio.ir/farsi-numbers-in-android-programming/">نمایش اعداد فارسی در View های اندروید</a> اولین بار در <a href="https://android-studio.ir">اندروید استودیو</a> پدیدار شد.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://android-studio.ir/farsi-numbers-in-android-programming/feed/</wfw:commentRss>
			<slash:comments>16</slash:comments>
		
		
			</item>
		<item>
		<title>نمایش صفحات وب در اکتیویتی توسط WebView</title>
		<link>https://android-studio.ir/android-webview/</link>
					<comments>https://android-studio.ir/android-webview/#comments</comments>
		
		<dc:creator><![CDATA[سیدمهدی مطهری]]></dc:creator>
		<pubDate>Mon, 08 Apr 2019 10:56:25 +0000</pubDate>
				<category><![CDATA[آموزش‌های تکمیلی]]></category>
		<category><![CDATA[آموزش‌های رایگان]]></category>
		<category><![CDATA[رابط_کاربری]]></category>
		<category><![CDATA[رابط_کاربری_اندروید]]></category>
		<guid isPermaLink="false">https://android-studio.ir/?p=155454</guid>

					<description><![CDATA[<p>به نام خدا. در این مبحث ابتدا به معرفی WebView در اندروید پرداخته سپس با نحوه فراخوانی و نمایش صفحات وب (HTML) آنلاین و آفلاین آشنا می‌شویم. WebView چیست؟ WebView یکی دیگر از View (Widget)های کاربردی پلتفرم اندروید است. توسط این View می‌توانیم یک صفحه‌ی وب آنلاین یا آفلاین (لوکال) را درون یک Activity به [&#8230;]</p>
<p>نوشته <a href="https://android-studio.ir/android-webview/">نمایش صفحات وب در اکتیویتی توسط WebView</a> اولین بار در <a href="https://android-studio.ir">اندروید استودیو</a> پدیدار شد.</p>
]]></description>
										<content:encoded><![CDATA[<p>به نام خدا. در این مبحث ابتدا به معرفی WebView در اندروید پرداخته سپس با نحوه فراخوانی و نمایش صفحات وب (HTML) آنلاین و آفلاین آشنا می‌شویم.</p>
<h2>WebView چیست؟</h2>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/webview/webview_in_android_operating_system.png" alt="آموزش کار با WebView در اندروید" /></p>
<p>WebView یکی دیگر از View (Widget)های کاربردی پلتفرم اندروید است. توسط این View می‌توانیم یک صفحه‌ی وب آنلاین یا آفلاین (لوکال) را درون یک Activity به کاربر نمایش دهیم. درست مانند باز کردن یک وب‌سایت در مرورگری مانند Chrome با این تفاوت که کاربر، صفحه وب را درون برنامه مشاهده می‌کند و به یک مرورگر مستقل منتقل نمی‌شود.<br />
در WebView امکان کنترل محتوای دریافتی از صفحه‌ی وب وجود دارد. به عنوان مثال می‌توانیم تعیین کنیم کدهای JavaScript (جاوا اسکریپت) که در طراحی صفحات وب با کدهای HTML ترکیب می‌شوند امکان اجرا داشته باشد یا خیر.</p>
<h2>کاربردهای WebView در اندروید</h2>
<p>کاربردهای متعددی را می‌توان برای این View ذکر کرد. یکی از مثال‌های بارز و پرکاربرد، نمایش نقشه‌های آنلاین مانند Google Maps است. اگر قصد دارید محل شرکت خود را روی یک نقشه نشان دهید، استفاده از <a href="http://android-studio.ir/android-webview/" target="_blank" rel="noopener noreferrer">WebView</a> یکی از گزینه‌های ساده و در دسترس است.<br />
یک کاربرد دیگر، نمایش محتوایی است که مرتب در حال تغییر و بروزرسانی است. تعدادی از اپلیکیشن‌های مطرح (ازجمله اینستاگرام) برای نمایش متن &#8220;شرایط و قوانین استفاده از اپلیکیشن&#8221; از یک <a href="http://android-studio.ir/android-webview/" target="_blank" rel="noopener noreferrer">وب ویو</a> استفاده می‌کنند. درنتیجه کاربر با مراجعه به این صفحه (اکتیویتی) متن قوانین را به صورت آنلاین و بروز از سرورهای اینستاگرام دریافت می‌کند. مزیت این روش در این است که برای اصلاح و بروزرسانی متن نیازی به انجام تغییرات درون خود برنامه و انتشار نسخه جدید نیست و کاربر بدون نیاز به بروزرسانی اپلیکیشن، هربار که قصد مطالعه قوانین برنامه را داشته باشد، آخرین نسخه را مشاهده می‌کند.<br />
یا فرض کنید یک وب‌سایت فروشگاهی راه اندازی کرده‌اید و به دلایلی (وقت کم، هزینه‌ی زیاد و&#8230;) امکان ساخت اپلیکیشن کامل آنرا ندارید. در اینجا به راحتی می‌توان همان وب‌سایت را در قالب یک اپلیکیشن موبایلی به کاربر عرضه کرد. درست مانند این است که کاربر وارد یک مرورگر شده و آدرس وب‌سایت شما را وارد کند. تنها تفاوت در این است که نیازی به وارد کردن آدرس نیست و به محض اجرای برنامه، وب‌سایت لود می‌شود.</p>
<div class="alert alert-warning">
<span class="notice">نکته:</span> استفاده از این قابلیت برای نمایش یک وب‌سایت کامل در قالب یک اپلیکیشن موبایلی، راهکار استانداردی نیست و تجربه کاربری (UX) قابل قبولی را رقم نمی‌زند. هنگامی از این راهکار استفاده کنید که هیچ گزینه‌ی دیگری روی میز نباشد! در این صورت وب‌سایت باید برای انواع صفحات نمایش بهینه شده باشد، یعنی پیاده سازی طراحی واکنشگرا (Responsive) الزامی است.
</div>
<p>در ادامه و در قالب یک پروژه شما را با WebView و قابلیت‌های آن آشنا می‌کنم.</p>
<h2>ساخت پروژه‌ WebView در اندروید استودیو</h2>
<p>یک <a href="http://android-studio.ir/create-android-project-and-its-structure/" target="_blank" rel="noopener noreferrer">پروژه‌ی جدید در اندروید استودیو</a> با نام WebView می‌سازم. اکتیویتی پیش فرض را از نوع Empty Activity انتخاب می‌کنم.<br />
همانطور که در مبحث <a href="http://android-studio.ir/android-retrofit-library/" target="_blank" rel="noopener noreferrer">آموزش کتابخانه Retrofit اندروید</a> اشاره شد، جهت امکان برقراری ارتباط بین اپلیکیشن و شبکه (اینترنت) نیاز به تعریف مجوز دسترسی (Permission) داریم. بنابراین مجوز مربوطه را به مانیفست پروژه اضافه می‌کنم:</p>
<p>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.webview&quot;&gt;

    &lt;uses-permission android:name=&quot;android.permission.INTERNET&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>سپس در لایه‌ی رابط کاربری اکتیویتی (UI) در حالت Design ویجت WebView را روی صفحه‌ی پیش نمایش کشیده (Drag &#038; drop) یا به صورت دستی و در حالت Text، تگ آنرا به Layout اضافه می‌کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/webview/webview_widget_in_android_studio.png" alt="ویجت WebView در اندروید استودیو" /></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;WebView
        android:id=&quot;@+id/web_view&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot; /&gt;

&lt;/RelativeLayout&gt;
</pre>
<p>حالا فایل جاوای اکتیویتی یعنی MainActivity.java را به صورت زیر تکمیل می‌کنم:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.webview;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.webkit.WebView;

public class MainActivity extends AppCompatActivity {

    private WebView mWebView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mWebView = findViewById(R.id.web_view);

        String siteUrl = &quot;https://android-studio.ir&quot;;
        mWebView.loadUrl(siteUrl);

    }
}
</pre>
<p>ابتدا یک شیء از کلاس WebView با نام دلخواه mWebView ساختم. سپس درون متد onCreate این شیء را به View مربوطه متصل کردم. در اینجا قصد دارم آدرس https://android-studio.ir را در این اکتیویتی نمایش دهم که این امر توسط متد loadUrl صورت می‌پذیرد. همانطور که از نام این متد پیداست، Url مدنظر ما بارگزاری (load) می‌شود. در نهایت محتوای این آدرس به mWebView که به ویجت web_view متصل شده ارسال می‌گردد.<br />
پروژه را اجرا می‌کنم. اگر شبیه ساز یا دیوایس دسترسی به اینترنت داشته و وب‌سایت نیز در دسترس باشد، باید محتوای آن را نمایش دهد.</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/webview/show_online_website_using_webview_in_android.png" alt="نمایش وب سایت در اپلیکیشن اندروید توسط WebView" /></p>
<p>صفحه‌ی وب با موفقیت درون اکتیویتی لود شده و می‌توانم به بالا و پایین اسکرول کنم.<br />
اگر هدف من از ساخت این اپلیکیشن، تبدیل وب‌سایت به یک برنامه‌ی موبایلی باشد شاید تنها کار لازم حذف <a href="http://android-studio.ir/android-toolbar-actionbar/" target="_blank" rel="noopener noreferrer">ActionBar</a> است که در مبحث <a href="http://android-studio.ir/android-toolbar-actionbar/" target="_blank" rel="noopener noreferrer">آموزش ساخت Toolbar در اندروید</a> با نحوه‌ی انجام آن آشنا شدیم. کافیست در فایل styles.xml استایل مربوط به Theme متریال پروژه را به Theme.AppCompat.Light.NoActionBar تغییر دهم:</p>
<p>styles.xml:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;style name=&quot;AppTheme&quot; parent=&quot;Theme.AppCompat.Light.NoActionBar&quot;&gt;
    &lt;!-- Customize your theme here. --&gt;
    &lt;item name=&quot;colorPrimary&quot;&gt;@color/colorPrimary&lt;/item&gt;
    &lt;item name=&quot;colorPrimaryDark&quot;&gt;@color/colorPrimaryDark&lt;/item&gt;
    &lt;item name=&quot;colorAccent&quot;&gt;@color/colorAccent&lt;/item&gt;
&lt;/style&gt;
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/webview/remove_actionbar_in_android_webview_activity.png" alt="حذف اکشن بار در اندروید استودیو" /></p>
<p>بجز loadUrl متدهای دیگری مانند canGoBack()، canGoForward()، clearHistory()، getUrl()، getTitle() و&#8230; قابل استفاده است که در صورت نیاز می‌توانید در مورد هرکدام جستجو کنید.<br />
در ابتدای مبحث گفتیم در WebView امکان کنترل و اعمال تنظیمات بر روی اجزای دریافتی از صفحه‌ی وب را داریم.<br />
به عنوان مثال اجرای کدهای جاوا اسکریپت (جاوا اسکریپت را با جاوا اشتباه نگیرید) به صورت پیش فرض غیر فعال است که این امر باعث می‌شود منوی سایت من باز نشود. زیرا باز و بسته شدن زیرمنوها توسط کتابخانه‌ی جی‌کوئری (jQuery) که با جاوا اسکریپت نوشته شده مدیریت و اجرا می‌شود. </p>
<pre class="brush: java; title: ; notranslate">
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mWebView = findViewById(R.id.web_view);

    String siteUrl = &quot;https://android-studio.ir&quot;;
    mWebView.loadUrl(siteUrl);

    mWebView.getSettings().setJavaScriptEnabled(true);

}
</pre>
<p>با استفاده از متد getSettings() امکان اجرای تنظیمات وسیعی وجود دارد که برای هرکدام یک متد مشخص تهیه شده. همانطور که در کد بالا ملاحظه می‌کنید با استفاده از متد setJavaScriptEnabled و مقدار true برای آن، کدهای جاوا اسکریپت فعال (Enable) می‌شوند. مجدد پروژه را Run یا Apply Changes می‌کنم تا تغییرات روی شبیه ساز بروزرسانی شود:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/webview/setJavaScriptEnabled_method.png" alt="متد setJavaScriptEnabled برای فعالسازی جاوا اسکریپت در WebView" /></p>
<p>متدهای دیگری نیز در اختیار توسعه دهنده قرار گرفته تا بتواند بر حسب نیاز خود، سایر قسمت‌ها را شخصی سازی کند:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/webview/webview_getsettings_methods.png" alt="متدهای مربوط به getSettings در WebView" /></p>
<p>برای مثال اولین مورد موجود در لیست (setDefaultFontSize) برای تعیین اندازه فونت بکار می‌رود.<br />
یا با استفاده از متدهای زیر، دکمه‌های زوم به صفحه اضافه می‌شوند:</p>
<pre class="brush: java; title: ; notranslate">
mWebView.getSettings().setSupportZoom(true);
mWebView.getSettings().setBuiltInZoomControls(true);
mWebView.getSettings().setDisplayZoomControls(true);
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/webview/setSupportZoom_method.png" alt="متد زوم setSupportZoom در WebView" /></p>
<p>(دکمه‌های Zoom هنگام اسکرول صفحه ظاهر می‌شوند)<br />
تعدادی دیگر از قابلیت‌ها را توسط متد setWebViewClient می‌توان مدیریت کرد. جهت مدیریت بهتر کدها ابتدا یک کلاس داخلی با نام دلخواه mWebViewClient درون اکتیویتی و بعد از بلاک مربوط به متد onCreate می‌سازم که از کلاس WebViewClient ارث بری می‌کند:</p>
<pre class="brush: java; title: ; notranslate">
public class MainActivity extends AppCompatActivity {

    private WebView mWebView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mWebView = findViewById(R.id.web_view);

        String siteUrl = &quot;https://android-studio.ir&quot;;
        mWebView.loadUrl(siteUrl);

        mWebView.getSettings().setJavaScriptEnabled(true);

        mWebView.getSettings().setSupportZoom(true);
        mWebView.getSettings().setBuiltInZoomControls(true);
        mWebView.getSettings().setDisplayZoomControls(true);

    }

    private class mWebViewClient extends WebViewClient {


    }

}
</pre>
<p>اولین متدی که به این کلاس اضافه می‌کنم مربوط به مدیریت کلیک روی لینک‌های موجود در صفحه‌ی وب است. روی لینک یکی از مطالب وب‌سایت کلیک می‌کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/webview/webview_browser_tester.png" alt="WebView Browser Tester" /></p>
<p>مشاهده می‌کنید صفحه‌ی جدید در قالب یک مرورگر با نام WebView Browser Tester باز شده که چندان مطلوب نیست. متد shouldOverrideUrlLoading لینک‌ها را مستقیما درون خود وب‌ویو لود کرده و به مرورگر دیگری منتقل نمی‌شود.</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/webview/webview_shouldOverrideUrlLoading_method.png" alt="متد shouldOverrideUrlLoading در WebView" /></p>
<p>از لیست متدی را انتخاب می‌کنم که پارامترهای ورودی آن از نوع WebView با نام view و String با نام url هستند. این متد با این دو پارامتر مدتیست از سوی اندروید منقضی یا Deprecated تلقی شده با اینحال همچنان استفاده می‌شود.</p>
<pre class="brush: java; title: ; notranslate">
private class mWebViewClient extends WebViewClient {

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {

        view.loadUrl(url);
        return true;

    }
}
</pre>
<p>متد را به اینصورت اصلاح و تکمیل کردم. حالا با لمس یا کلیک روی هر لینک، آدرس موردنظر در قالب url توسط loadUrl لود و به view منتقل شده که باعث می‌شود صفحه‌ی جدید مستقیما درون WebView نمایش داده شود.<br />
قبل از اجرا و تست این متد، دو متد پرکاربرد دیگر را معرفی می‌کنم. متدهای onPageStarted و onPageFinished به ترتیب، زمان بارگزاری صفحه و پایان این پروسه را برمی‌گردانند. </p>
<pre class="brush: java; title: ; notranslate">
private class mWebViewClient extends WebViewClient {

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {

        view.loadUrl(url);
        return true;

    }

    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        super.onPageStarted(view, url, favicon);
    }

    @Override
    public void onPageFinished(WebView view, String url) {
        super.onPageFinished(view, url);
    }
    
}
</pre>
<p>برای مثال می‌توان در متد onPageStarted یک ProgressBar را اجرا کرده و در onPageFinished آنرا متوقف نمود. با اینحال برای درک بهتر و همچنین به حاشیه نرفتن مبحث آموزشی، از Toast استفاده می‌کنم:</p>
<pre class="brush: java; title: ; notranslate">
private class mWebViewClient extends WebViewClient {

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {

        view.loadUrl(url);
        return true;

    }

    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {

        Toast.makeText(MainActivity.this, &quot;Loading page...&quot;, Toast.LENGTH_SHORT).show();

    }

    @Override
    public void onPageFinished(WebView view, String url) {

        Toast.makeText(MainActivity.this, &quot;Loading finished&quot;, Toast.LENGTH_SHORT).show();
        
    }

}
</pre>
<p>در نهایت متد setWebViewClient را درون onCreate تعریف کرده و ورودی آنرا کلاس mWebViewClient قرار می‌دهم:</p>
<pre class="brush: java; title: ; notranslate">
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mWebView = findViewById(R.id.web_view);

    String siteUrl = &quot;https://android-studio.ir&quot;;
    mWebView.loadUrl(siteUrl);

    mWebView.getSettings().setJavaScriptEnabled(true);

    mWebView.getSettings().setSupportZoom(true);
    mWebView.getSettings().setBuiltInZoomControls(true);
    mWebView.getSettings().setDisplayZoomControls(true);

    mWebView.setWebViewClient(new mWebViewClient());

}
</pre>
<p>پروژه را اجرا کرده و روی یک لینک کلیک می‌کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/webview/webview_onPageStarted_method.png" alt="آموزش کار با متد onPageStarted در WebView" /></p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/webview/webview_onPageFinished_method.png" alt="آموزش کار با متد onPageFinished در WebView" /></p>
<p>مشاهده می‌کنید صفحه‌ی جدید درون خود WebView بارگزاری شد نه یک مرورگر. همچنین پیغام‌های بارگزاری (Loading page…) و اتمام بارگزاری (Loading finished) را می‌بینید که در قالب Toast چاپ شده‌اند.</p>
<p>سورس کامل MainActivity.java:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.webview;

import androidx.appcompat.app.AppCompatActivity;

import android.graphics.Bitmap;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private WebView mWebView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mWebView = findViewById(R.id.web_view);

        String siteUrl = &quot;https://android-studio.ir&quot;;
        mWebView.loadUrl(siteUrl);

        mWebView.getSettings().setJavaScriptEnabled(true);

        mWebView.getSettings().setSupportZoom(true);
        mWebView.getSettings().setBuiltInZoomControls(true);
        mWebView.getSettings().setDisplayZoomControls(true);

        mWebView.setWebViewClient(new mWebViewClient());

    }

    private class mWebViewClient extends WebViewClient {

        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {

            view.loadUrl(url);
            return true;

        }

        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {

            Toast.makeText(MainActivity.this, &quot;Loading page...&quot;, Toast.LENGTH_SHORT).show();

        }

        @Override
        public void onPageFinished(WebView view, String url) {

            Toast.makeText(MainActivity.this, &quot;Loading finished&quot;, Toast.LENGTH_SHORT).show();

        }

    }

}
</pre>
<h2>نمایش صفحات HTML محلی و آفلاین در WebView</h2>
<p>در قسمت قبل محتوای مدنظر ما از یک url و بصورت آنلاین دریافت می‌شد که مستلزم برقراری ارتباط اینترنتی بود. اما ممکن است در مواردی نیاز به نمایش محتوایی با فرمت وب و HTML بصورت آفلاین داشته باشیم. به عنوان مثال طراحی یک یا چند صفحه‌ی خاص از اپلیکیشن برای توسعه دهنده‌ای که با اصول طراحی صفحات وب نیز آشناست، ممکن است پیاده سازی آن در فرمت HTML و CSS ساده‌تر از کار با Layout های اندروید باشد. یا ممکن است شخص بخواهد یک اپلیکیشن کتابچه را به‌طور کامل توسط صفحات وب پیاده‌سازی کند. محتوای این صفحات، ایستا (استاتیک) است و نیازی به اتصال به سرور نیست.<br />
در این روش فایل‌های مرتبط با صفحات وب را در فولدر assets پروژه قرار می‌دهیم. این فولدر به صورت پیش‌فرض وجود ندارد. برای ساخت آن در قسمت نمایش ساختار پروژه روی app راست کلیک کرده و مسیر<br />
New > Folder > Assets Folder<br />
را دنبال کرده و در پنجره‌ی باز شده Finish بزنید تا فولدر ساخته شود:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/webview/add_assets_folder_to_android_studio_project.png" alt="ساخت فولدر assets در پروژه اندروید استودیو" /></p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/webview/assets_added_to_android_project.png" alt="اضافه کردن فولدر assets در پروژه اندروید استودیو" /></p>
<p>همچنین می‌توان این کار را در خارج از محیط <a href="http://android-studio.ir/" target="_blank" rel="noopener noreferrer">اندروید استودیو</a> و در محل قرارگیری پروژه، این فولدر را اضافه کرد:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/webview/add_assets_folder_in_file_explorer.png" alt="ساخت فولدر assets در File Explorer سیستم عامل" /></p>
<p>من یک صفحه‌ی ساده‌ی وب ساختم که شامل یک فایل html و یک css است:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/webview/local_html_to_show_in_webview.png" alt="نمایش فایل HTML لوکال در WebView اندروید" /></p>
<p>این دو فایل را کپی کرده و در محیط اندروید استودیو یا File explorer سیستم عامل درون فولدر paste می‌کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/webview/html_file_added_to_assets_android_project.png" alt="اضافه کردن صفحات وب HTML به فولدر assets در اندروید استودیو" /></p>
<p>در مرحله آخر برای اجرای این فایلِ محلی بجای url وب‌سایت، آدرس زیر را در siteUrl جایگزین آدرس وب‌سایت می‌کنم:</p>
<pre class="brush: java; title: ; notranslate">
String siteUrl = &quot;file:///android_asset/index.html&quot;;
</pre>
<p>به اینصورت فایل index.html موجود در فولدر assets پروژه اندرویدی در WebView اجرا می‌شود:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/webview/load_local_html_in_android_application.png" alt="نمایش صفحات وب آفلاین در WebView اندروید" /></p>
<p>در این پروژه صرفا جهت آشنایی با نحوه‌ی اضافه کردن صفحات وب به اپلیکیشن یک صفحه‌ی HTML بسیار ساده را استفاده کردم اما پیچیده‌ترین صفحات وب (شامل متن، تصویر، کدهای جاوا اسکریپت و..) را به تعداد زیاد و نامحدود می‌توان در اپلیکیشن‌های اندرویدی بکار برد.</p>
<h3>مطالعه‌ی بیشتر:</h3>
<p style="text-align: left; direction: ltr;">
<a href="https://developer.android.com/reference/android/webkit/WebView" target="_blank" rel="noopener noreferrer">https://developer.android.com/reference/android/webkit/WebView</a><br />
<a href="https://developer.android.com/reference/android/webkit/WebSettings" target="_blank" rel="noopener noreferrer">https://developer.android.com/reference/android/webkit/WebSettings</a><br />
<a href="https://developer.android.com/guide/webapps/webview" target="_blank" rel="noopener noreferrer">https://developer.android.com/guide/webapps/webview</a>
</p>
<p class="source">توجه: سورس پروژه درون پوشه 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/WebView.zip" class="button green edd-submit">دانلود رایگان با حجم ۲ مگابایت</a> <a href="http://dl2.android-studio.ir/courses/WebView.zip" class="button red edd-submit">لینک کمکی</a>
</div>
<p>نوشته <a href="https://android-studio.ir/android-webview/">نمایش صفحات وب در اکتیویتی توسط WebView</a> اولین بار در <a href="https://android-studio.ir">اندروید استودیو</a> پدیدار شد.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://android-studio.ir/android-webview/feed/</wfw:commentRss>
			<slash:comments>120</slash:comments>
		
		
			</item>
		<item>
		<title>کار با GridLayout در اندروید</title>
		<link>https://android-studio.ir/android-gridlayout-viewgroup/</link>
					<comments>https://android-studio.ir/android-gridlayout-viewgroup/#comments</comments>
		
		<dc:creator><![CDATA[سیدمهدی مطهری]]></dc:creator>
		<pubDate>Mon, 25 Feb 2019 23:25:50 +0000</pubDate>
				<category><![CDATA[آموزش‌های تکمیلی]]></category>
		<category><![CDATA[آموزش‌های رایگان]]></category>
		<category><![CDATA[رابط_کاربری]]></category>
		<category><![CDATA[رابط_کاربری_اندروید]]></category>
		<guid isPermaLink="false">https://android-studio.ir/?p=153147</guid>

					<description><![CDATA[<p>در جلسات گذشته با ViewGroup هایی مانند RelativeLayout، LinearLayout و TableLayout آشنا شدیم و توانستیم رابط‌های کاربری متفاوتی را توسط این Layout ها ایجاد کنیم. در این مبحث قصد دارم یک ViewGroup دیگر با نام GridLayout را معرفی کنم. GridLayout چیست؟ به نام خدا. در اندروید ۴٫۰ (API 14) یک ViewGroup جدید با نام GridLayout [&#8230;]</p>
<p>نوشته <a href="https://android-studio.ir/android-gridlayout-viewgroup/">کار با GridLayout در اندروید</a> اولین بار در <a href="https://android-studio.ir">اندروید استودیو</a> پدیدار شد.</p>
]]></description>
										<content:encoded><![CDATA[<p>در جلسات گذشته با ViewGroup هایی مانند <a href="http://android-studio.ir/android-user-interface/" target="_blank" rel="noopener noreferrer">RelativeLayout</a>، LinearLayout و <a href="http://android-studio.ir/android-tablelayout/" target="_blank" rel="noopener noreferrer">TableLayout</a> آشنا شدیم و توانستیم رابط‌های کاربری متفاوتی را توسط این Layout ها ایجاد کنیم. در این مبحث قصد دارم یک ViewGroup دیگر با نام GridLayout را معرفی کنم.</p>
<h2>GridLayout چیست؟</h2>
<p>به نام خدا. در اندروید ۴٫۰ (API 14) یک ViewGroup جدید با نام GridLayout معرفی شد. Grid به معنای طراحی شبکه‌ای و سلولی است. مانند یک جدول که از تعدادی سطر و ستون تشکیل شده.</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/gridlayout/android_gridlayout_viewgroup.png" alt="آموزش GridLayout در اندروید" /></p>
<p>البته اصطلاح GridLayout منحصر به سیستم عامل اندروید نیست و اگر این واژه را در گوگل جستجو کنید به مثال‌هایی در سایز زمینه‌ها مانند CSS در طراحی صفحات وب برخورد خواهید کرد.<br />
اگر مبحث TableLayout را فراموش کرده‌اید مجدد یک مرور کلی روی آن داشته باشید تا تفاوت بین این دو را بهتر درک کنید. در TableLayout صرفا امکان مدیریت View ها (به عبارتی، سلول‌ها)ی موجود در یک سطر را داشتیم و می‌توانستیم چند سطر یا ردیف زیر یکدیگر ایجاد کنیم. اما در GridLayout مدیریت ستون‌ها نیز امکان‌پذیر است. به عنوان مثال می‌توان ستون‌های دو سطر را با یکدیگر ادغام کرد. یک View مانند Button می‌تواند یک یا چند سلول را در جهت افقی یا عمودی اشغال کند. همچنین می‌توان یک سلول را از یک سطر به سطر دیگر (و از یک ستون به ستون دیگر) منتقل کرد.<br />
علی‌رقم کاربردهای فراوان این ViewGroup، در منابع آموزشی کمتر به آن پرداخته شده که در این مبحث سعی می‌کنم تا حد امکان توضیحات کامل ارائه دهم.</p>
<h2>مزایای GridLayout</h2>
<p>GridLayout عمدتا در طراحی لایه‌های پیچیده کاربرد دارد. لایه‌هایی که پیاده سازی آنها توسط سایر ViewGroup ها سخت و در مواردی غیر ممکن است. Layout ای که با GridLayout به راحتی ساخته می‌شود در سایر ViewGroup ما را با یک Layout تو در تو و عمیق مواجه می‌کند که این عمیق بودن خود باعث کاهش کارایی (Performance) برنامه می‌شود. همانطور که قبلا اشاره شد، در اینجا مدیریت ستون‌ها نیز به سادگی امکان‌پذیر است و به طور کلی انعطاف بیشتری در پیاده‌سازی لایه‌های پیچیده داریم.<br />
اگر بخواهم ویژگی‌های این Layout را به صورت خلاصه بیان کنم، در سه گزینه خلاصه می‌شود:</p>
<ul>
<li>امکان کنترل و مدیریت سلول‌ها در هردو جهت سطر (Row) و ستون (Column)</li>
<li>اجرای لایه‌های پیچیده بدون استفاده از Layout های تو در تو و در نتیجه بهینه بودن لایه</li>
<li>ساخت ساده‌ی لایه‌هایی که از نظم و ترتیب مشخصی پیروی نمی‌کنند</li>
</ul>
<h2>ساخت پروژه‌ی GridLayout</h2>
<p>یک پروژه با نام GridLayout در <a href="http://android-studio.ir/" target="_blank" rel="noopener noreferrer">اندروید استودیو</a> با یک Empty Activity ایجاد می‌کنم و با ارائه‌ی چند مثال، به تشریح این ViewGroup می‌پردازم.</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/gridlayout/gridlayout_in_android_studio_pallete.png" alt="GridLayout در پالت اندروید استودیو" /></p>
<p>در پالت اندروید استودیو گزینه‌ی GridLayout قرار دارد که با کشیدن و رها کردن روی صفحه‌ی پیش نمایش، به لایه‌ی اکتیویتی اضافه می‌شود. اما من این کار را انجام نمی‌دهم زیرا این گزینه مربوط به کتابخانه Support است که با افزودن آن به پروژه، خط زیر به build.gradle اضافه می‌شود:</p>
<pre class="brush: java; title: ; notranslate">
implementation 'com.android.support:gridlayout-v7:xx.x.x'
</pre>
<p>در رابط کاربری اکتیویتی نیز تگ XML زیر ایجاد می‌شود:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;android.support.v7.widget.GridLayout&gt;

&lt;/android.support.v7.widget.GridLayout&gt;
</pre>
<p>همانطور که در ابتدای مبحث اشاره شد، GridLayout در API 14 معرفی شد. استفاده از این کتابخانه در صورتی لازم است که اپلیکیشن ما روی دیوایس‌های API 14 به قبل نیز استفاده شود در صورتی که در زمان تهیه این آموزش، حدود ۱۰۰% دیوایس‌های اندرویدی بالای این نسخه هستند.<br />
Layout موجود در activity_main.xml را حذف کرده و یک GridLayout جایگزین آن می‌کنم:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;GridLayout
    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    android:layout_width=&quot;wrap_content&quot;
    android:layout_height=&quot;wrap_content&quot;&gt;

    &lt;TextView
        android:text=&quot;Cell 1&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 2&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 3&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 4&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 5&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 6&quot;/&gt;

&lt;/GridLayout&gt;
</pre>
<p>کد فوق، ساده ترین حالت است. در اینجا ۶ عدد TextView داریم که هرکدام نقش یک سلول را برای GridLayout ایفا می‌کند.<br />
پروژه را روی شبیه ساز اجرا می‌کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/gridlayout/simple_gridlayout.png" alt="آموزش ساخت GridLayout در اندروید" /></p>
<p>سلول‌ها به صورت افقی پشت یکدیگر قرار گرفته‌اند. در این ViewGroup نحوه چینش سلول‌ها را می‌توان در دو حالت horizontal (افقی) و vertical (عمودی) تعیین کرد. در قسمت قبل من خاصیت orientation را تعریف نکردم که به صورت پیش فرض مقدار horizontal برای آن درنظر گرفته شده.<br />
مقدار vertical را اضافه می‌کنم:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;GridLayout
    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    android:layout_width=&quot;wrap_content&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:orientation=&quot;vertical&quot;&gt;

    &lt;TextView
        android:text=&quot;Cell 1&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 2&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 3&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 4&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 5&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 6&quot;/&gt;

&lt;/GridLayout&gt;
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/gridlayout/vertical_cell_view.png" alt="سلول های GridLayout در حالت vertical" /></p>
<p>مشاهده می‌کنید سلول‌ها به صورت عمودی زیر یکدیگر قرار گرفتند.<br />
در GridLayout دو خاصیت rowCount و columnCount به ترتیب برای تعیین حداکثر تعداد سطر و ستون استفاده می‌شود.<br />
من مجدد حالت چینش را horizontal و برای columnCount مقدار ۳ تعیین می‌کنم تا سلول‌ها در سه ستون قرار گیرند:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;GridLayout
    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    android:layout_width=&quot;wrap_content&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:orientation=&quot;horizontal&quot;
    android:columnCount=&quot;3&quot;&gt;

    &lt;TextView
        android:text=&quot;Cell 1&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 2&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 3&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 4&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 5&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 6&quot;/&gt;

&lt;/GridLayout&gt;
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/gridlayout/columnCount_attribute.png" alt="خاصیت columnCount در GridLayout اندروید" /></p>
<p>قبل از ادامه کار ابتدا یک استایل به TextView ها اضافه می‌کنم تا نتیجه تغییرات واضح‌تر باشد.<br />
استایل زیر را در styles.xml ساختم:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;style name=&quot;Cells&quot;&gt;
    &lt;item name=&quot;android:background&quot;&gt;#FF9800&lt;/item&gt;
    &lt;item name=&quot;android:padding&quot;&gt;3dp&lt;/item&gt;
    &lt;item name=&quot;android:layout_marginLeft&quot;&gt;3dp&lt;/item&gt;
    &lt;item name=&quot;android:layout_marginTop&quot;&gt;3dp&lt;/item&gt;
&lt;/style&gt;
</pre>
<p>حالا استایل را به ویجت‌ها اضافه می‌کنم:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;GridLayout
    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    android:layout_width=&quot;wrap_content&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:orientation=&quot;horizontal&quot;
    android:columnCount=&quot;3&quot;&gt;

    &lt;TextView
        android:text=&quot;Cell 1&quot;
        style=&quot;@style/Cells&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 2&quot;
        style=&quot;@style/Cells&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 3&quot;
        style=&quot;@style/Cells&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 4&quot;
        style=&quot;@style/Cells&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 5&quot;
        style=&quot;@style/Cells&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 6&quot;
        style=&quot;@style/Cells&quot;/&gt;

&lt;/GridLayout&gt;
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/gridlayout/add_style_to_gridlayout_cells.png" alt="تعریف استایل برای سلول های GridLayout" /></p>
<p>در حال حاضر چینش سلول‌ها به صورت افقی است. یعنی ۳ سلول اول در سطر اول و ۳ سلول دوم در سطر دوم. حالا می‌خواهم ترتیب قرارگیری به صورت ستونی باشد. Orientation را تغییر داده و rowCount را با مقدار ۲ اضافه می‌کنم تا تعداد سطرها تغییر نکند:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;GridLayout
    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    android:layout_width=&quot;wrap_content&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:orientation=&quot;vertical&quot;
    android:columnCount=&quot;3&quot;
    android:rowCount=&quot;2&quot;&gt;

    &lt;TextView
        android:text=&quot;Cell 1&quot;
        style=&quot;@style/Cells&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 2&quot;
        style=&quot;@style/Cells&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 3&quot;
        style=&quot;@style/Cells&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 4&quot;
        style=&quot;@style/Cells&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 5&quot;
        style=&quot;@style/Cells&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 6&quot;
        style=&quot;@style/Cells&quot;/&gt;

&lt;/GridLayout&gt;
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/gridlayout/rowCount_attribute.png" alt="خاصیت rowCount در GridLayout" /></p>
<p>برای ادامه‌ی آموزش orientation را به حالت افقی برمی‌گردانم.<br />
کلمه longer را به text پنجم اضافه می‌کنم تا طولانی‌تر شود:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;GridLayout
    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    android:layout_width=&quot;wrap_content&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:orientation=&quot;horizontal&quot;
    android:columnCount=&quot;3&quot;
    android:rowCount=&quot;2&quot;&gt;

    &lt;TextView
        android:text=&quot;Cell 1&quot;
        style=&quot;@style/Cells&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 2&quot;
        style=&quot;@style/Cells&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 3&quot;
        style=&quot;@style/Cells&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 4&quot;
        style=&quot;@style/Cells&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 5 longer&quot;
        style=&quot;@style/Cells&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 6&quot;
        style=&quot;@style/Cells&quot;/&gt;

&lt;/GridLayout&gt;
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/gridlayout/gridlayout_fill_horizontal.png" alt="خاصیت layout_gravity در اندروید" /></p>
<p>در ابتدای مبحث گفتیم یکی از مزایای GridLayout امکان مدیریت ستون‌هاست. در تصویر بالا ملاحظه می‌کنید طول Cell2 از سلول ۵ کوتاهتر است و مقداری فضای خالی ایجاد شده که لازم است این فضای خالی پر شود. برای اینکار خاصیت layout_gravity با مقدار fill_horizontal را به سلول‌های این ستون اضافه می‌کنم:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;GridLayout
    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    android:layout_width=&quot;wrap_content&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:orientation=&quot;horizontal&quot;
    android:columnCount=&quot;3&quot;
    android:rowCount=&quot;2&quot;&gt;

    &lt;TextView
        android:text=&quot;Cell 1&quot;
        style=&quot;@style/Cells&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 2&quot;
        style=&quot;@style/Cells&quot;
        android:layout_gravity=&quot;fill_horizontal&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 3&quot;
        style=&quot;@style/Cells&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 4&quot;
        style=&quot;@style/Cells&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 5 longer&quot;
        style=&quot;@style/Cells&quot;
        android:layout_gravity=&quot;fill_horizontal&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 6&quot;
        style=&quot;@style/Cells&quot;/&gt;

&lt;/GridLayout&gt;
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/gridlayout/gridlayout_fill_horizontal_2.png" alt="fill_horizontal برای layout_gravity" /></p>
<p>یک ردیف دیگر اضافه می‌کنم تا نتیجه را بهتر درک کنید:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;GridLayout
    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    android:layout_width=&quot;wrap_content&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:orientation=&quot;horizontal&quot;
    android:columnCount=&quot;3&quot;
    android:rowCount=&quot;3&quot;&gt;

    &lt;TextView
        android:text=&quot;Cell 1&quot;
        style=&quot;@style/Cells&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 2&quot;
        style=&quot;@style/Cells&quot;
        android:layout_gravity=&quot;fill_horizontal&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 3&quot;
        style=&quot;@style/Cells&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 4&quot;
        style=&quot;@style/Cells&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 5 more longer&quot;
        style=&quot;@style/Cells&quot;
        android:layout_gravity=&quot;fill_horizontal&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 6&quot;
        style=&quot;@style/Cells&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 7&quot;
        style=&quot;@style/Cells&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 8 longer&quot;
        style=&quot;@style/Cells&quot;
        android:layout_gravity=&quot;fill_horizontal&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 9&quot;
        style=&quot;@style/Cells&quot;/&gt;

&lt;/GridLayout&gt;
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/gridlayout/gridlayout_fill_horizontal_3.png" alt="fill_horizontal برای layout_gravity" /></p>
<p>تمام سلول‌های موجود در ستون دوم به اندازه‌ی بزرگترین سلول کشیده شده‌اند.<br />
یکی دیگر از قابلیت‌های لایه‌ی گرید، امکان جابجایی و تغییر موقعیت سلول‌هاست. به عنوان مثال می‌توان مکان Cell 2 و Cell 5 را تغییر داد بطوری که هرکدام در جای دیگری قرار گیرد. این کار توسط دو خاصیت layout_row و layout_column انجام می‌شود. به کد و خروجی زیر دقت کنید:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;GridLayout
    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    android:layout_width=&quot;wrap_content&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:orientation=&quot;horizontal&quot;
    android:columnCount=&quot;3&quot;
    android:rowCount=&quot;3&quot;&gt;

    &lt;TextView
        android:text=&quot;Cell 1&quot;
        style=&quot;@style/Cells&quot; /&gt;

    &lt;TextView
        android:text=&quot;Cell 2&quot;
        style=&quot;@style/Cells&quot;
        android:layout_gravity=&quot;fill_horizontal&quot;
        android:layout_row=&quot;1&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 3&quot;
        style=&quot;@style/Cells&quot;
        android:layout_row=&quot;0&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 4&quot;
        style=&quot;@style/Cells&quot; /&gt;

    &lt;TextView
        android:text=&quot;Cell 5 more longer&quot;
        style=&quot;@style/Cells&quot;
        android:layout_gravity=&quot;fill_horizontal&quot;
        android:layout_row=&quot;0&quot;
        android:layout_column=&quot;1&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 6&quot;
        style=&quot;@style/Cells&quot;
        android:layout_row=&quot;1&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 7&quot;
        style=&quot;@style/Cells&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 8 longer&quot;
        style=&quot;@style/Cells&quot;
        android:layout_gravity=&quot;fill_horizontal&quot;/&gt;

    &lt;TextView
        android:text=&quot;Cell 9&quot;
        style=&quot;@style/Cells&quot;/&gt;

&lt;/GridLayout&gt;
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/gridlayout/layout_row_&#038;_layout_column.png" alt="خاصیت های layout_row و layout_column در GridLayout" /></p>
<div class="alert alert-warning">
<span class="notice">نکته:</span> شمارش سطر و ستون از عدد ۰ آغاز می‌شود. یعنی موقعیت سلول در سطر اول/ستون اول برابر است با (۰٫۰)
</div>
<p>ابتدا برای Cell 2 خاصیت layout_row با مقدار ۱ تعریف کردم تا این سلول در سطر دوم قرار گیرد. با انجام این تغییر، Cell 3 نیز به سطر دوم منتقل می‌شود که با تعریف layout_row برای این سلول و قرار دادن مقدار ۰، مجدد به سطر اول باز می‌گردد. در ادامه موقعیت Cell 5 را تعیین می‌کنم. مقدار ۰ برای layout_row و مقدار ۱ برای layout_column این سلول را در سطر اول/ستون دوم قرار می‌دهد. مانند مرحله قبل که با جابجایی Cell 2 سلول بعد از آن یعنی Cell 3 نیز جابجا شد، در اینجا هم Cell 6 به همراه Cell 5 جابجا می‌شود که با layout_row و مقدار ۱ مجدد آنرا به سطر دوم باز می‌گردانم. اینجاست که انعطاف پذیری بالای این ViewGroup ثابت می‌شود.</p>
<p>یک Activity دیگر از نوع Empty Activity با نام Calculator به پروژه اضافه می‌کنم. هنگام ساخت اکتیویتی، Launcher Activity را انتخاب می‌کنم تا به عنوان اکتیویتی اصلی در شبیه ساز اجرا شود. همانطور که از نام اکتیویتی پیداست، در این مرحله با یک ماشین حساب سروکار داریم.</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/gridlayout/calculator.png" alt="ساخت دکمه های ماشین حساب در اندروید با GridLayout" /></p>
<p>قصد دارم دکمه‌های این ماشین حساب را با GridLayout پیاده سازی کنم. ۱۴ دکمه‌ که در یک Grid با ۴ سطر و ۴ ستون قرار گرفته‌اند. </p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;GridLayout
    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    android:layout_width=&quot;wrap_content&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:orientation=&quot;horizontal&quot;
    android:columnCount=&quot;4&quot;
    android:rowCount=&quot;4&quot;&gt;

    &lt;Button /&gt;
    &lt;Button /&gt;
    &lt;Button /&gt;
    &lt;Button /&gt;
    &lt;Button /&gt;
    &lt;Button /&gt;
    &lt;Button /&gt;
    &lt;Button /&gt;
    &lt;Button /&gt;
    &lt;Button /&gt;
    &lt;Button /&gt;
    &lt;Button /&gt;
    &lt;Button /&gt;
    &lt;Button /&gt;

&lt;/GridLayout&gt;
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/gridlayout/add_14_button_to_gridlayout.png" alt="اضافه کردن Button ها در اندروید" /></p>
<p>کاری که باید انجام دهم این است که دو دکمه را به نحوی ویرایش کنم که هرکدام به اندازه‌ی دو دکمه ی معمولی جا بگیرد. یکی در جهت افقی و دیگری در جهت عمودی. در اینجا از دو خاصیت layout_rowSpan و layout_columnSpan استفاده می‌کنم. لغت Span به معنی طول است بنابراین خاصیت اولی برای تعیین طول سطر و دومی برای طول ستون بکار می‌رود.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;GridLayout
    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    android:layout_width=&quot;wrap_content&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:orientation=&quot;horizontal&quot;
    android:columnCount=&quot;4&quot;
    android:rowCount=&quot;4&quot;&gt;

    &lt;Button
        android:layout_columnSpan=&quot;2&quot;
        android:layout_gravity=&quot;fill&quot;/&gt;
    &lt;Button /&gt;
    &lt;Button /&gt;
    &lt;Button /&gt;
    &lt;Button /&gt;
    &lt;Button /&gt;
    &lt;Button /&gt;
    &lt;Button /&gt;
    &lt;Button /&gt;
    &lt;Button /&gt;
    &lt;Button
        android:layout_rowSpan=&quot;2&quot;
        android:layout_gravity=&quot;fill&quot;/&gt;
    &lt;Button /&gt;
    &lt;Button /&gt;
    &lt;Button /&gt;

&lt;/GridLayout&gt;
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/gridlayout/gridlayout_layout_columnSpan_&#038;_layout_rowSpan_attributes.png" alt="خاصیت های layout_columnSpan و layout_rowSpan" /></p>
<p>برای دکمه اول خاصیت layout_columnSpan با مقدار ۲ تعیین کردم. یعنی این ویجت باید به اندازه‌ی دو ستون فضا در اختیار داشته باشد. سپس توسط layout_gravity و مقدار fill، دکمه تمام فضای خالی موجود را اشغال می‌کند. به همین ترتیب برای دکمه‌ی یازدهم layout_rowSpan و layout_gravity تعریف می‌کنم که در نهایت این دکمه به اندازه دو سطر طول دارد.</p>
<div class="alert alert-warning">
<span class="notice">نکته:</span> در این مثال من بجای fill_horizontal و fill_vertical تنها از fill استفاده کردم که در هردو مشترک است و تفاوتی نمی‌کند از کدام مقدار استفاده کنیم.
</div>
<div class="alert alert-warning">
<span class="notice">تمرین:</span> سعی کنید مثال فوق را توسط LinearLayout یا RelativeLayout و یا TableLayout پیاده سازی کرده، سپس حجم کد XML و زمانی که برای هردو صرف شده را مقایسه کنید.
</div>
<p>در مثال آخر یک فرم ورود (Login Form) را توسط GridLayout طراحی می‌کنم.<br />
یک اکتیویتی دیگر با نام Form به پروژه اضافه می‌کنم.<br />
ابتدا کد و خروجی شبیه ساز را درج کرده سپس به توضیح جزئیات می‌پردازم:<br />
activity_form.xml:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;GridLayout
    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;
    android:columnCount=&quot;4&quot;&gt;

    &lt;TextView
        android:layout_row=&quot;0&quot;
        android:layout_column=&quot;0&quot;
        android:layout_columnSpan=&quot;4&quot;
        android:layout_gravity=&quot;center_horizontal&quot;
        android:text=&quot;ورود&quot;
        android:textSize=&quot;30sp&quot; /&gt;

    &lt;TextView
        android:layout_row=&quot;1&quot;
        android:layout_column=&quot;0&quot;
        android:layout_columnSpan=&quot;4&quot;
        android:layout_gravity=&quot;right&quot;
        android:text=&quot; لطفا نام کاربری و رمز عبور را وارد کنید:&quot;
        android:textSize=&quot;17sp&quot; /&gt;

    &lt;Space
        android:layout_row=&quot;2&quot;
        android:layout_column=&quot;0&quot;
        android:layout_columnSpan=&quot;4&quot;
        android:layout_height=&quot;30dp&quot; /&gt;

    &lt;TextView
        android:layout_row=&quot;3&quot;
        android:layout_column=&quot;0&quot;
        android:layout_gravity=&quot;right&quot;
        android:text=&quot;نام کاربری&quot; /&gt;

    &lt;EditText
        android:ems=&quot;10&quot; /&gt;

    &lt;TextView
        android:layout_row=&quot;4&quot;
        android:layout_column=&quot;0&quot;
        android:layout_gravity=&quot;right&quot;
        android:text=&quot;رمز عبور&quot; /&gt;

    &lt;EditText
        android:ems=&quot;10&quot; /&gt;

    &lt;Space
        android:layout_row=&quot;5&quot;
        android:layout_column=&quot;0&quot;
        android:layout_columnSpan=&quot;4&quot;
        android:layout_height=&quot;30dp&quot; /&gt;

    &lt;Button
        android:layout_row=&quot;6&quot;
        android:layout_column=&quot;0&quot;
        android:layout_columnSpan=&quot;4&quot;
        android:layout_gravity=&quot;center_horizontal&quot;
        android:text=&quot;ورود&quot; /&gt;

    &lt;Space
        android:layout_row=&quot;7&quot;
        android:layout_column=&quot;0&quot;
        android:layout_columnSpan=&quot;4&quot;
        android:layout_gravity=&quot;fill&quot; /&gt;

    &lt;Button
        android:layout_row=&quot;8&quot;
        android:layout_column=&quot;0&quot;
        android:layout_columnSpan=&quot;4&quot;
        android:layout_gravity=&quot;fill_horizontal&quot;
        android:text=&quot;رمز عبور را فراموش کرده ام&quot; /&gt;

&lt;/GridLayout&gt;
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/gridlayout/use_space_attribute_in_gridlayout.png" alt="تگ Space در اندروید" /></p>
<p>در GridLayout برای ایجاد فاصله بین سلول‌ها بجای خاصیت‌ margin از تگ Space استفاده می‌کنیم. در واقع Space خود به عنوان یک سلول به Grid اضافه می‌شود.<br />
چند خاصیت دیگر برای این ViewGroup تعریف شده که useDefaultMargins یکی از آنهاست. این خاصیت یک فاصله‌ی پیش فرض بین سلول‌ها ایجاد می‌کند. البته در صورتی که قبلا فاصله‌ای تعریف نکرده باشیم.<br />
خط زیر را به تگ GridLayout اضافه می‌کنم:</p>
<pre class="brush: xml; title: ; notranslate">
android:useDefaultMargins=&quot;true&quot;
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/gridlayout/useDefaultMargins_attribute.png" alt="خاصیت useDefaultMargins در GridLayout اندروید" /></p>
<p>اسکرین شات فوق را با تصویر قبل مقایسه کنید. اندکی فضای خالی مابین سلول‌ها ایجاد شده.<br />
سایر ویژگی‌ها را صرفا معرفی می‌کنم:</p>
<table class="table table-striped" style="text-align: center;">
<thead>
<tr>
<th>خاصیت</th>
<th>توضیح</th>
</tr>
</thead>
<tbody>
<tr>
<td dir="ltr">android:columnOrderPreserved</td>
<td>اگر مقدار “true” تعیین شود عرض ستون بر اساس محتوای درون آن تنظیم می‌گردد ولی چنانچه “false” تعیین شود به نحوی تنظیم می‌شود تا سایر ستون‌ها نیز در وضعیت مناسبی قرار گیرند.</td>
</tr>
<tr>
<td dir="ltr">android:rowOrderPreserved</td>
<td>اگر مقدار “true” تعیین شود ارتفاع سطر بر اساس محتوای درون آن تنظیم می‌گردد ولی چنانچه “false” تعیین شود به نحوی تنظیم می‌شود تا سایر سطرها نیز در وضعیت مناسبی قرار گیرند.</td>
</tr>
</tbody>
</table>
<h3>مطالعه‌ی بیشتر:</h3>
<p style="text-align: left; direction: ltr;">
<a href="https://developer.android.com/reference/android/widget/GridLayout" target="_blank" rel="noopener noreferrer">https://developer.android.com/reference/android/widget/GridLayout</a><br />
<a href="https://developer.android.com/reference/android/widget/GridLayout.LayoutParams.html" target="_blank" rel="noopener noreferrer">https://developer.android.com/reference/android/widget/GridLayout.LayoutParams.html</a>
</p>
<p class="source">توجه : سورس پروژه درون پوشه 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/gridlayout.zip" class="button green edd-submit">دانلود رایگان با حجم ۱٫۱ مگابایت</a> <a href="http://dl2.android-studio.ir/courses/gridlayout.zip" class="button red edd-submit">لینک کمکی</a>
</div>
<p>نوشته <a href="https://android-studio.ir/android-gridlayout-viewgroup/">کار با GridLayout در اندروید</a> اولین بار در <a href="https://android-studio.ir">اندروید استودیو</a> پدیدار شد.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://android-studio.ir/android-gridlayout-viewgroup/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>تغییر فونت در کل برنامه اندروید یا قسمتی از آن</title>
		<link>https://android-studio.ir/set-custom-fonts-on-android-applications/</link>
					<comments>https://android-studio.ir/set-custom-fonts-on-android-applications/#comments</comments>
		
		<dc:creator><![CDATA[سیدمهدی مطهری]]></dc:creator>
		<pubDate>Sun, 01 Jul 2018 15:15:01 +0000</pubDate>
				<category><![CDATA[آموزش‌های تکمیلی]]></category>
		<category><![CDATA[آموزش‌های رایگان]]></category>
		<category><![CDATA[رابط_کاربری]]></category>
		<guid isPermaLink="false">https://android-studio.ir/?p=109223</guid>

					<description><![CDATA[<p>به‌نام خدا. یکی از نیازهای ضروری یک اپلیکیشن، بخصوص اپلیکیشن‌های فارسی زبان، امکان استفاده از فونت‌های دلخواه در برنامه است. پیاده سازی فونت در اندروید به روش‌های مختلفی قابل انجام است که در این مبحث سه روش را بررسی می‌کنیم. ابتدا یک پروژه جدید با نام CustomFont و یک Empty Activity ایجاد می‌کنم. تغییر فونت [&#8230;]</p>
<p>نوشته <a href="https://android-studio.ir/set-custom-fonts-on-android-applications/">تغییر فونت در کل برنامه اندروید یا قسمتی از آن</a> اولین بار در <a href="https://android-studio.ir">اندروید استودیو</a> پدیدار شد.</p>
]]></description>
										<content:encoded><![CDATA[<p>به‌نام خدا. یکی از نیازهای ضروری یک اپلیکیشن، بخصوص اپلیکیشن‌های فارسی زبان، امکان استفاده از فونت‌های دلخواه در برنامه است. پیاده سازی فونت در اندروید به روش‌های مختلفی قابل انجام است که در این مبحث سه روش را بررسی می‌کنیم.</p>
<p>ابتدا یک پروژه جدید با نام CustomFont و یک Empty Activity ایجاد می‌کنم.</p>
<h2>تغییر فونت Widget ها در XML:</h2>
<p>همزمان با معرفی API 26 قابلیت جدیدی در اندروید استودیو نسخه ۳ اضافه شد که امکان تعیین فونت برای widget ها بدون نیاز به استفاده از متدهای جاوا و تنها با افزودن خاصیت fontFamily به هر ویجت را فراهم می‌کند. این قابلیت از API 16 به بالا پشتیبانی می‌کند که لازم است کتابخانه appcompat-v7 حتما در پروژه وجود داشته باشد.<br />
ابتدا می‌بایست یک دایرکتوری با نام font به res اضافه کنیم:</p>
<p style="text-align: left; direction: ltr;">
Res > New > Android Resource Directory
</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/font/add_font_directory_to_res_android_project.png" alt="ساخت فولدر فونت در پروژه اندروید" /></p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/font/add_font_directory_to_res_android_project_2.png" alt="ساخت فولدر فونت در پروژه اندروید" /></p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/font/add_font_directory_to_res_android_project_3.png" alt="ساخت فولدر font در پروژه اندروید" /></p>
<p>حالا فایل فونت یا فونت‌های مدنظر (با پسوند .ttf یا .otf) را درون این دایرکتوری قرار می‌دهم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/font/add_font_file_to_android_project_font_directory.png" alt="افزودن فایل ttf یا otf فونت به پروژه اندروید" /></p>
<div class="alert alert-warning">
<span class="notice">تذکر:</span> در نامگذاری فایل فونت فقط از حروف کوچک، اعداد و زیرخط (underline) استفاده کنید.
</div>
<p>در نهایت توسط خاصیت fontFamily فونت را به یک TextView اضافه می‌کنم. خروجی را قبل و بعد از تعریف این خاصیت مشاهده می‌کنید:</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;
    android:padding=&quot;8dp&quot;&gt;


    &lt;TextView
        android:id=&quot;@+id/txt_one&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:text=&quot; متن شماره یک&quot;
        android:textAlignment=&quot;center&quot;
        android:fontFamily=&quot;@font/mitra&quot;
        android:textSize=&quot;30sp&quot;/&gt;


&lt;/LinearLayout&gt;
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/font/change_widget_font_using_fontFamily_attribute.png" alt="تغییر فونت ویجت اندروید توسط خاصیت fontFamily" /></p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/font/change_widget_font_using_fontFamily_attribute_2.png" alt="تغییر فونت ویجت اندروید توسط خاصیت fontFamily" /></p>
<p>امکانی جهت پیش نمایش فونت در محیط اندروید استودیو فراهم گردیده که با دابل کلیک روی فونت، ادیتور باز شده و می‌توانید متن دلخواه را تایپ کنید:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/font/font_preview_in_android_studio.png" alt="پیش نمایش فونت در اندروید استودیو" /></p>
<h2>ست کردن فونت توسط Typeface:</h2>
<p>در این قسمت می‌خواهم در اکتیویتی و توسط کلاس Typeface فونت مدنظرم را به id ویجت مربوطه ارسال کنم. یک TextView با شناسه txt_two به صفحه اضافه می‌کنم:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;TextView
    android:id=&quot;@+id/txt_two&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:text=&quot; متن شماره دو&quot;
    android:textAlignment=&quot;center&quot;
    android:textSize=&quot;30sp&quot;/&gt;
</pre>
<p>در ادامه اکتیویتی را به اینصورت تکمیل می‌کنم:</p>
<p>MainActivity.java:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.customfont;

import android.graphics.Typeface;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    TextView txtTwo;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        txtTwo = findViewById(R.id.txt_two);
        Typeface tf = getResources().getFont(R.font.afaaq);
        txtTwo.setTypeface(tf);

    }
}
</pre>
<p>در خط اول TextView در اکتیویتی تعریف شده. در خط دوم یک نمونه از Typeface ساخته شده که توسط متد getFont() فونت afaaq از دایرکتوری font (یعنی R.font) فراخوانی شده است. (پوشه font در دایرکتوری res قرار گرفته بنابراین قبل از getFont() متد getResources() نوشته شده. در نهایت توسط متد setTypeface() فونتی که در tf تعریف شده را روی txtTwo اعمال می‌کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/font/change_font_using_typeface_and_getFont_method.png" alt="تغییر فونت در برنامه اندروید توسط Typeface و getFont" /></p>
<p>در قسمت متد getFont یک ارور داریم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/font/getFont_method_min_sdk_api_26.png" alt="متد getFont در API 26 و بالاتر اجرا می‌شود" /></p>
<p>این متد در API 26 و به بالا قابل استفاده است. یعنی اگر پروژه را روی یک دیوایس پایینتر از API 26 اجرا کنم، <a href="http://android-studio.ir/set-custom-fonts-on-android-applications/" target="_blank" rel="noopener noreferrer">تغییر فونت</a> اعمال نمی‌شود و با توجه به اینکه MinSDK پروژه را روی ۱۷ قرار داده‌ام، این مسئله برای تعداد زیادی از کاربران ایجاد مشکل کرده و بجای فونت مدنظر من، فونت پیش فرض دیوایس خود را مشاهده خواهند کرد. استفاده از این متد در زمانی مناسب است که MinSDK پروژه حداقل ۲۶ باشد.<br />
پس ناچارا لازم است Typeface را به صورت دیگری پیاده سازی کنیم. از متدی با نام createFromAsset استفاده می‌کنم که البته فایل فونت را از فولدر assets می‌گیرد. من این فولدر را در پروژه ندارم بنابراین ابتدا آنرا ایجاد می‌کنم:</p>
<p style="text-align: left; direction: ltr;">
app > New > Folder > Assets Folder
</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/font/add_assets_folder_to_android_project.png" alt="ساخت فولدر assets در پروژه اندرویدی" /></p>
<p>در پنجره ی باز شده با انتخاب گزینه Finish فولدر اضافه می‌شود:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/font/assets_folder_added_to_project.png" alt="ساخت فولدر assets در پروژه اندرویدی" /></p>
<p>حالا باید فونت را مجدد به این فولدر هم اضافه کنم. اینکه فایل فونت مستقیما درون assets قرار گیرد یا داخل یک فولدر ویژه فونت، تفاوتی نمی‌کند اما من برای مرتب بودن پروژه، یک فولدر با نام fonts به assets اضافه کرده و همان فونت قبل یعنی afaaq.ttf را درون آن قرار می‌دهم:</p>
<p style="text-align: left; direction: ltr;">
assets > New > Directory
</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/font/add_font_folder_to_assets.png" alt="افزودن فایل فونت به assets" /></p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/font/add_font_folder_to_assets_2.png" alt="افزودن فایل فونت به assets" /></p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/font/add_font_file_to_assets.png" alt="افزودن فایل فونت به assets" /></p>
<p>(فونت را از فولدر font قبلی copy و اینجا paste کردم)</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.customfont;

import android.graphics.Typeface;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    TextView txtTwo, txtThree;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // getFont Method
        txtTwo = findViewById(R.id.txt_two);
        Typeface tf = getResources().getFont(R.font.afaaq);
        txtTwo.setTypeface(tf);

        // createFromAsset Method
        txtThree = findViewById(R.id.txt_three);
        Typeface atf = Typeface.createFromAsset(getAssets(), &quot;fonts/afaaq.ttf&quot;);
        txtThree.setTypeface(atf);

    }
}
</pre>
<pre class="brush: xml; title: ; notranslate">
&lt;TextView
    android:id=&quot;@+id/txt_three&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:text=&quot; متن شماره سه&quot;
    android:textAlignment=&quot;center&quot;
    android:textSize=&quot;30sp&quot;/&gt;
</pre>
<p>ملاحظه می‌کنید TextView سوم با شناسه txt_three تعریف و توسط متد createFromAsset() فونت موجود در مسیر fonts/afaaq.ttf دایرکتوری assets روی آن اعمال شد:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/font/Typeface_using_createFromAsset_method.png" alt="تغییر فونت در اندروید توسط Typeface و createFromAsset" /></p>
<h2>تغییر فونت در کل برنامه توسط کتابخانه Calligraphy:</h2>
<p>در روش‌هایی که تاکنون بررسی شد، برای هر ویجت باید فونت را جداگانه تعریف می‌کردیم. برای اپلیکیشنی که تعداد کمی ویجت دارد یا قصد اعمال فونت فقط در تعداد محدودی از ویجت‌ها را داریم، این روش‌ها ساده و مناسب خواهد بود. اما در مواردی که در حال توسعه یک اپلیکیشن با اکتیویتی‌ها و ویجت‌های متعدد هستیم و لازم است فونت روی همه آنها اعمال شود، استفاده از روش‌های فوق منطقی نیست و علاوه بر صرف زمان زیاد، احتمال خطا را نیز افزایش می‌دهد. در اینصورت لازم است راهی را انتخاب کنیم که بتوان یک فونت را در سراسر پروژه تعریف کرد بدون آنکه نیاز به اعمال تغییرات روی تک تک ویجت‌ها (مانند TextView، <a href="http://android-studio.ir/android-toolbar-actionbar/" target="_blank" rel="noopener noreferrer">Toolbar</a>، Menu و&#8230;) باشیم.<br />
در حال حاضر متداول‌ترین راه برای این کار، استفاده از کتابخانه‌ی Calligraphy است که توسط شخصی با نام Christopher Jenkins تهیه و در گیت هاب و به صورت رایگان در دسترس توسعه دهندگان قرار گرفته است:</p>
<p style="text-align: left; direction: ltr;">
<a href="https://github.com/chrisjenx/Calligraphy" target="_blank" rel="noopener noreferrer">https://github.com/chrisjenx/Calligraphy</a>
</p>
<div class="alert alert-warning">
<span class="notice">تذکر:</span> در حدود دو ماه قبل از نگارش این آموزش، توسعه دهنده این کتابخانه نسخه جدید کتابخانه را در صفحه جدیدی در گیت هاب با عنوان Calligraphy 3 معرفی و اعلام کرده نسخه فعلی بروزرسانی نخواهد شد. با اینحال من از همین نسخه رایج فعلی یعنی ۲٫۳٫۰ استفاده می‌کنم. نسخه جدید تفاوت محسوسی در پیاده سازی و استفاده نداشته و با مطالعه این مبحث، از نسخه ۳ نیز می‌توانید استفاده کنید.
</div>
<p>مطابق توضیحات موجود در صفحه گیت هاب، کتابخانه را به بلاک dependencies در 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.1.1'
    compile 'uk.co.chrisjenx:calligraphy:2.3.0'
}
</pre>
<p>در قدم بعد لازم است یک کلاس به پکیج اصلی پروژه اضافه کرده و سپس آنرا از کلاس Application ارث بری کنیم. یک کلاس با نام دلخواه Calligraphy ایجاد کردم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/font/add_calligraphy_class_to_android_project.png" alt="ایجاد کلاس Calligraphy در پروژه اندروید" /></p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.customfont;

import android.app.Application;

public class Calligraphy extends Application {

}
</pre>
<p>سپس یک متد onCreate() به صورت زیر به کلاس اضافه می‌کنم:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.customfont;

import android.app.Application;

import uk.co.chrisjenx.calligraphy.CalligraphyConfig;

public class Calligraphy extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        CalligraphyConfig.initDefault(new CalligraphyConfig.Builder()
                .setDefaultFontPath(&quot;fonts/yekan.ttf&quot;)
                .setFontAttrId(R.attr.fontPath)
                .build()
        );

    }

}
</pre>
<p>کد متد را می‌توانید از سورس پروژه یا صفحه گیت هاب کتابخانه کپی کرده و فقط مسیر فونت مدنظر خود را در ورودی setDefaultFontPath() اصلاح کنید. به جهت تشخیص بهتر، از یک فونت متفاوت با دو فونت قبل استفاده می‌کنم. این کتابخانه نیز فونت را از assets می‌خواند بنابراین فونت yekan.ttf را مانند مرحله قبل به assets/fonts اضافه کردم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/font/add_font_for_calligraphy_library.png" alt="اضافه کردن فونت به پروژه اندروید برای استفاده در کتابخانه Calligraphy" /></p>
<p>لازم است این کلاس را در مانیفست پروژه (AndroidManifest.xml) توسط خاصیت android:name معرفی کنیم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/font/define_Calligraphy_class_in_manifest.png" alt="تعریف کلاس Calligraphy در 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.customfont&quot;&gt;

    &lt;application
        android:name=&quot;.Calligraphy&quot;
        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>حالا کافیست متد زیر را در اکتیویتی یا اکتیویتی‌هایی که قصد داریم از این فونت تاثیر بپذیرند اضافه کنیم:</p>
<pre class="brush: java; title: ; notranslate">
@Override
protected void attachBaseContext(Context newBase) {
    super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase));
}
</pre>
<p>MainActivity.java:</p>
<pre class="brush: java; title: ; notranslate">
package ir.android_studio.customfont;

import android.content.Context;
import android.graphics.Typeface;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.widget.TextView;

import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper;

public class MainActivity extends AppCompatActivity {

    TextView txtTwo, txtThree;
    Toolbar mToolbar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        //Toolbar
        mToolbar = findViewById(R.id.m_toolbar);
        setSupportActionBar(mToolbar);

        //getFont Method
        txtTwo = findViewById(R.id.txt_two);
        Typeface tf = getResources().getFont(R.font.afaaq);
        txtTwo.setTypeface(tf);

        //createFromAsset Method
        txtThree = findViewById(R.id.txt_three);
        Typeface atf = Typeface.createFromAsset(getAssets(), &quot;fonts/afaaq.ttf&quot;);
        txtThree.setTypeface(atf);

    }

    @Override
    protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase));
    }

}
</pre>
<p>من یک <a href="http://android-studio.ir/android-toolbar-actionbar/" target="_blank" rel="noopener noreferrer">Toolbar</a> جایگزین اکشن‌بار پیش فرض کردم تا نتیجه را بهتر درک کنید.</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;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
    android:orientation=&quot;vertical&quot;
    tools:context=&quot;.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:titleTextColor=&quot;#fff&quot;
        app:popupTheme=&quot;@style/ThemeOverlay.AppCompat.Dark&quot; /&gt;

    &lt;TextView
        android:id=&quot;@+id/txt_one&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:text=&quot; متن شماره یک&quot;
        android:textAlignment=&quot;center&quot;
        android:fontFamily=&quot;@font/mitra&quot;
        android:textSize=&quot;30sp&quot;/&gt;

    &lt;TextView
        android:id=&quot;@+id/txt_two&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:text=&quot; متن شماره دو&quot;
        android:textAlignment=&quot;center&quot;
        android:textSize=&quot;30sp&quot;/&gt;

    &lt;TextView
        android:id=&quot;@+id/txt_three&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:text=&quot; متن شماره سه&quot;
        android:textAlignment=&quot;center&quot;
        android:textSize=&quot;30sp&quot;/&gt;

    &lt;TextView
        android:id=&quot;@+id/txt_four&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:text=&quot; متن شماره چهار&quot;
        android:textAlignment=&quot;center&quot;
        android:textSize=&quot;30sp&quot;/&gt;

    &lt;Button
        android:id=&quot;@+id/button&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:text=&quot;متن دکمه&quot; /&gt;


&lt;/LinearLayout&gt;
</pre>
<p>یک TextView دیگر با شناسه txt_four و یک Button در صفحه قرار دادم که نه از طریق xml و نه java فونتی روی آن اعمال نشده.<br />
پروژه را اجرا می‌کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/font/set_font_on_whole_android_project_using_calligraphy_library.png" alt="تغییر فونت کل برنامه و پروژه اندروید توسط کتابخانه Calligraphy" /></p>
<p>ملاحظه می‌کنید title تولبار، TextView چهارم و Button، فونت yekan که در کالیگرافی تعریف شده را نشان می‌دهند. حتی TextView اول که فونت mitra در xml اعمال شده بود نیز فونت yekan را نمایش می‌دهد. یعنی فونت Calligraphy روی همه آیتم‌های درون اکتیویتی اعمال می‌شود مگر اینکه توسط Typeface فونتی متفاوت از آن تعریف شده باشد (مانند TextView شماره دو و سه).<br />
با استفاده از Calligraphy هم می‌توان مستقیم و بدون نیاز به کدهای جاوا، روی ویجت‌ها و از طریق xml فونت اعمال کرد. اینکار عینا مانند روش xml ابتدای مبحث انجام می‌شود با این تفاوت که به‌جای خاصیت fontFamily از fontPath استفاده می‌کنیم و فایل فونت نیز باید در assets قرار گرفته باشد. یک فونت دیگر با نام beirut.ttf به فولدر fonts در assets اضافه می‌کنم:</p>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/font/add_new_font_to_assets.png" alt="افزودن فونت به assets" /></p>
<p>سپس یک دکمه دیگر به صفحه اضافه کرده و فونت را توسط fontPath تعریف می‌کنم:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;Button
    android:id=&quot;@+id/button_two&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:text=&quot;متن دکمه دوم&quot;
    fontPath=&quot;fonts/beirut.ttf&quot;/&gt;
</pre>
<p><img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/font/fontPath_attribute.png" alt="تغییر فونت یک ویجت در اندروید توسط fontPath" /></p>
<p>دکمه دوم فونت beirut را نشان می‌دهد.<br />
شاید این سوال برایتان پیش آمده که تفاوت این روش و روش اول مبحث که هردو توسط یک خاصیت در xml انجام می‌شوند چیست و ما باید کدام گزینه را انتخاب کنیم؟<br />
یک اصل کلی در توسعه برنامه‌ها (چه در بستر موبایل، وب و یا دسکتاپ) این است که تا حد امکان استفاده از کتابخانه‌ها و پلاگین‌ها به حداقل برسد ترجیحا از امکانات داخلی ای که در اختیار داریم بهره ببریم تا هم حجم برنامه و هم ایرادات، باگ‌ها و تداخلات احتمالی کتابخانه‌ها با سایر اجزای پروژه به حداقل برسد. یعنی در اینجا اگر نیازی به تغییر فونت سراسر پروژه نداشته و تنها چند ویجت محدود باید تغییر کند، بهتر است از کتابخانه Calligraphy صرف نظر نموده و از راهکارهای داخلی اندروید مانند xml و Typeface استفاده کنیم. اما در صورتی که نیاز به تغییر فونت کل پروژه بود، ناگزیر به استفاده از این کتابخانه هستیم و همانطور که در صفحات قبل مشاهده کردید، با اعمال فونت توسط کتابخانه، ویجتی که توسط fontFamily تعریف شده بود در عمل این خاصیت را از دست داده و فونت جدید در واقع روی آن Override می‌شود. بنابراین در این شرایط، برای تغییر یک یا چند ویجت محدود، می‌بایست از خاصیت xml مربوط به خود کتابخانه یعنی fontPath و یا Typeface بهره گرفت.<br />
طبیعتا خاصیت مربوط به فونت را می‌توان در یک style نیز تعریف کرد تا لازم نباشد برای تک تک ویجت‌های مدنظر جداگانه تعریف گردد:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;style name=&quot;CustomFontStyle&quot;&gt;
    &lt;item name=&quot;fontPath&quot;&gt;fonts/beirut.ttf&lt;/item&gt;
&lt;/style&gt;
</pre>
<p>با تعریف استایل فوق، هر ویجت و کامپوننتی که استایل CustomFontStyle را بپذیرد فونت نیز اعمال خواهد شد:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;Button
    android:id=&quot;@+id/button_two&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:text=&quot;متن دکمه دوم&quot;
    style=&quot;@style/CustomFontStyle&quot;/&gt;
</pre>
<div class="alert alert-warning">
<span class="notice">نکته:</span> خاصیت fontPath بدون پیشوند android: یا app: بوده و به همین دلیل اندروید استودیو اخطاری با همین مضمون اعلام می‌کند که جای نگرانی نیست و خللی در کار ایجاد نمی‌کند. با اینحال اگر تمایل دارید این اخطار از محیط IDE شما حذف شود، راهکار آن در صفحه گیت‌هاب کتابخانه ذکر شده است.<br />
<img decoding="async" class="aligncenter img-responsive" src="http://android-studio.ir/wp-content/uploads/font/fontPath_prefix_error.png" alt="خطای مربوط به خاصیت fontPath در اندروید استودیو" />
</div>
<div class="alert alert-warning">
<span class="notice">تذکر:</span> در انتخاب فونت دقت کنید. هر فونتی مناسب استفاده در اپلیکیشن نیست. برای مثال فونت‌های آفاق و بیروت که من در این مبحث استفاده کردم، بجز در موارد خاص (استفاده‌های فانتزی)، نتیجه مطلوبی نخواهد داشت. در حال حاضر فونت <a href="http://fontiran.com/?p=255" rel="nofollow noopener noreferrer" target="_blank">ایران سنس</a> بیشترین استفاده را در بین اپ های فارسی زبان دارد که به دلیل رعایت حق مولف در این پروژه استفاده نکردم. در صورت تمایل به استفاده از این فونت لازم است لایسنس آن را از fontiran.com خریداری کنید.
</div>
<p><span class="notice">توجه :</span> سورس پروژه درون پوشه Exercises قرار داده شده است</p>
<p><span class="notice">منابع تکمیلی:</span></p>
<p style="text-align: left; direction: ltr;">
<a href="https://github.com/chrisjenx/Calligraphy" target="_blank" rel="noopener noreferrer">https://github.com/chrisjenx/Calligraphy</a><br />
<a href="https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml" target="_blank" rel="noopener noreferrer">https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml</a><br />
<a href="https://developer.android.com/reference/android/graphics/Typeface" target="_blank" rel="noopener noreferrer">https://developer.android.com/reference/android/graphics/Typeface</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/custom_font.zip" class="button green edd-submit">دانلود رایگان با حجم ۱/۴ مگابایت</a> <a href="http://dl2.android-studio.ir/courses/custom_font.zip" class="button red edd-submit">لینک کمکی</a>
</div>
<p>نوشته <a href="https://android-studio.ir/set-custom-fonts-on-android-applications/">تغییر فونت در کل برنامه اندروید یا قسمتی از آن</a> اولین بار در <a href="https://android-studio.ir">اندروید استودیو</a> پدیدار شد.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://android-studio.ir/set-custom-fonts-on-android-applications/feed/</wfw:commentRss>
			<slash:comments>28</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>
	</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-10 21:35:57 by W3 Total Cache
-->