سبد (0)

اجزای یک صفحه در اندروید

اجزای یک صفحه

همانطور که می دانید اکتیویتی پایه ای ترین جز یک برنامه ی اندرویدی است.اکتیویتی رابط کاربری برنامه ی شما را نشان می دهد که ممکن است شامل قسمت هایی مثل Buttonها, Lable ها, textBox ها,...باشد.معمولاً رابط کاربری را در یک فایل XML مثل main.xml که در پوشه ی res/layout قرار دارد تعریف می کنید.که شبیه کدهای زیر است: 

 

<?xml version=”1.0” encoding=”utf-8”?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
android:orientation=”vertical”
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
>
<TextView
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=”@string/hello”
/>
</LinearLayout>

در زمان اجرا,شما رابط کاربری XML را در متد رویداد()onCreate کلاس Activity با استفاده از متد ()setContentView بارگذاری می کنید:

 

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}

 در زمان کامپایل برنامه هر کدام از عناصر موجود در فایل XML به یکی از کلاس های GUI اندروید به همراه خصوصیاتی که بوسیله ی متدها تنظیم شده,کامپایل می شود.سیستم اندروید زمانی که اکتیویتی بارگذاری می گردد,رابط کاربری را ایجاد می کند.

ایجاد رابط کاربری در فایل XML بسیار آسان است,اما گاهی نیاز است که رابط کاربری پویایی را در زمان اجرا ایجاد کرد(برای مثال زمانی که در حال ساخت بازی هستید) با این قابلیت شما می توانید رابط کاربری خود را در زمان اجرا ایجاد کنید.

یک اکتیویتی شامل View ها و گروه های ابزاری نمایش می باشد.یک View ویجتی است که روی صفحه قرار دارد.نمونه هایی از Viewها مثل Button ها, Lable ها, TextBox ها را می توان نام برد.یک View از کلاس پایه ی android.view.View برگرفته شده است.یک یا چند View  را می توان با هم در یک گروه ابزار نمایش قرار داد.یک گروه ابزار (که خود نوعی از View ها است) فضایی را جهت چینش و مرتب سازی View ها فراهم می کند.به عنوان مثال یک گروه ابزاری شامل LinearLayout و FrameLayout ها هستند.یک گروه ابزار نمایش از کلاس پایه ی android.view.ViewGroup برگرفته شده است.اندروید از گروه ابزار نمایش زیر پشتیبانی می کند:

  • LinearLayout
  • AbsoluteLayout
  • TableLayout
  • RelativeLayout
  • FrameLayout
  • ScrollView

به این نکته توجه داشته باشید که میتوانید از تلفیق چند گروه ابزاری رابط کاربری خود را ایجاد کنید.

LinearLayout

LinearLayout ها View ها را در یک ردیف یا یک ستون چینش می کند.ابزار های نمایش می توانند به عنوان فرزند در LinearLayout به صورت افقی یا عمودی چیده شوند.

برای اینکه ببینید LinearLayout ها به صورتی کار می کنند,تغییرات زیر را در فایل main.xml اعمال کنید:

 

<?xml version=”1.0” encoding=”utf-8”?>
<LinearLayout
xmlns:android=”http://schemas.android.com/apk/res/android”
android:orientation=”vertical”
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
>
<TextView
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=”@string/hello”
/>
</LinearLayout>

در فایل main.xml می بینید که عنصر ریشه <LinearLayout> است که عنصر<TextView> درون آن قرار دارد.عنصر <LinearLayout> اولویت نمایش ابزار های نمایشی که درون آن قرار دارند را کنترل می کند.هر ابزار نمایش یا گروه ابزارها یکسری خصوصیات عمومی به شرح زیر دارند:

layout_width -- عرض ابزار نمایش یا ViewGroup را مشخص می کند.

layout_height -- طول ابزار نمایش یا ViewGroup را مشخص می کند.

layout_marginTop -- فضای اضافه ی لبه ی بالای ابزار نمایش یا ViewGroup را مشخص می کند.

layout_matginBottom -- فضای اضافه ی لبه ی پایین ابزار نمایش یا ViewGroup را مشخص می کند.

layout_marginLeft -- فضای اضافه ی لبه ی سمت چپ ابزار نمایش یا ViewGroup را مشخص می کند.

layout_marginRight -- فضای اضافه ی لبه ی سمت راست ابزار نمایش یا ViewGroup را مشخص می کند.

 layout_gravity -- چگونگی قرارگیری ابزارهای نمایشی فرزند را مشخص می کند.

layout_weight -- نشان دهنده ی فضای اضافی است که می تواند به ابزار نمایش اختصاص یابد.

layout_x -- جهت افقی ابزار نمایش یا گروه ابزار را مشخص می کند.

layout_y -- جهت عمودی ابزار نمایش یا گروه ابزار را مشخص می کند.

 بعضی از این خصوصیات تنها زمانی کاربرد دارند که ابزار نمایش در گروه ابزار خاصی قرار گیرد.به عنوان مثال خصوصیات layout_weight و layout_gravity فقط وقتی کاربرد دارند که یک ابزار نمایش در LinearLayout یا TableLayout قرار گیرند.

 برای مثال عرض عنصر <TextView> با استفاده از ثابت fill_parent تمام عرض والد خود یا صفحه نمایش را پر می کند.ارتفاع آن به وسیله ی wrap_content مشخص می شود و به این معنی است که ارتفاع این عنصر به اندازه ی ارتفاع محتویات آن یا ارتفاع متن است.اگر نمی خواهید که <TextView> تمام ردیف را اشغال کند,میتوانید خصوصیت layout_width را برابر wrap_content قرار دهید:


< TextView
android:layout_width=”wrap_content
android:layout_height=”wrap_content”
android:text=”@string/hello”
/>

 با استفاده از کد بالا ,عرض View به اندازه ی عرض متن موجود در آن تنظیم می شود.

به کد زیر دقت کنید:

 

<?xml version=”1.0” encoding=”utf-8”?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
android:orientation=”vertical”
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
>
<TextView
android:layout_width=”105dp”
android:layout_height=”wrap_content”
android:text=”@string/hello”
/>
<Button
android:layout_width=”160dp”
android:layout_height=”wrap_content”
android:text=”Button”
/>
</LinearLayout>

 در اینجا طول هردو عنصر TextView و Button را به وسیله ی مقادیر مطلق تنظیم کردیم.در این مثال عرض TextView معادل 100dp و عرض Button معادل 160dp در نظر گرفته شده است.

واحدهای اندازه گیری

وقتی که در حال مشخص کردن اندازه ی عناصر رابط کاربری خود هستید باید با واحد اندازه گیری آشنایی داشته باشید.

  • Density-independent pixel -- dp : :یک dp برابر است با یک پیکسل در صفحه نمایش 160dpi .این واحد اندازه گیری  برای تنظیم رابط کاربری شما مناسب است.صفحه نمایش 160dpi حالت پایه و پیشفرض برای اندروید محسوب می شود.برای نشان دادن واحد اندازه گیری می توانید از dp یا dpi استفاده کنید.
  • Scale-independent pixel --sp :مشابه dp است و برای تعیین اندازه فونت ها بکار می رود.
  • Point -- pt :یک واحد پوینت 1.72 اینچ است.که بر مبنای اندازه ی فیزیکی صفحه به دست می آید.
  • Pixel -- px : بستگی دارد به اندازه ی پیکسل در صفحه نمایش.استفاده از این واحد اندازه گیری توصیه نمی شود.چون ممکن است در دستگاه های مختلف با رزولوشن های مختلف اجرا نشود.

چگالی صفحه نمایش بستگی به اندازه ی صفحه و رزولوشن آن دارد.در اندروید چگالی صفحه نمایش ها به چند دسته تقسیم شده اند:

  • 120dpi --Low density             ldpi
  • 160dpi -- Medium density           mdpi
  • 240dpi -- High density            hdpi
  • 320dpi -- Extra High density           xhdpi

هر دستگاهی در یکی از این دسته ها قرار می گیرد.برای مثال Nexus s در دسته ی hdpi قرار دارد چون چگالی آن نزدیک به 240 است.دستگاه HTC Hero دارای یک صفحه نمایش 3.2 اینچی با رزولوشن 320 در 480 است که حدوداً با چگالی 180dpi کار می کند.این دستگاه در دسته ی mdpi قرار می گیرد چون چگالی آن نزدیک به 160dpi است.

تبدیل کردن DP به PX

فرمول تبدیل dp به px به صورت زیر است:

 

Actual Pixel = dp*(dpi/160)

که در آن dpi برابر است با 120 یا 160 یا 240 یا 320 است.برای پیدا کردن مقدار پیکسلی viewها از متد ()getWidth و شئ view استفاده کنید:

 

public void onClick(View view)
Toast.makeText(this, String.valueOf(view,getWidth()), Toast.LENGTH_LONG).show();

AbsoluteLayout

AbsoluteLayout به شما این قابلیت را می دهد تا محل قطعی فرزندش را به صورت دقیق مشخص کنید.فایل main.xml را به صورت زیر ویرایش کنید:

 

<?xml version=”1.0” encoding=”utf-8”?>
<AbsoluteLayout
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
xmlns:android=”http://schemas.android.com/apk/res/android”
>
<Button
android:layout_width=”188dp”
android:layout_height=”wrap_content”
android:text=”Button”
android:layout_x=”126px”
android:layout_y=”361px”
/>
<Button
android:layout_width=”113dp”
android:layout_height=”wrap_content”
android:text=”Button”
android:layout_x=”12px”
android:layout_y=”361px”
/>
</AbsoluteLayout>

مشکل اساسی که در استفاده از AbsoluteLayout پیش می اید زمانی است که اکتیویتی شما در صفحه نمایشی با رزولوشن بالا اجرا شود.این روش قدیمی از اندروید 1.5 برجای مانده و پیشنهاد می شود که از AbsoluteLayout در رابط کاربری خود استفاده نکنید.چون هیچ تضمینی برای اجرای درست و صحیح آن در نسخه های مختلف اندروید وجود ندارد.به جای آن می توانید از دیگر روش های مطرح شده استفاده کنید.

TableLayout

TableLayout می تواند ابزارهای نمایش را در ستون و ردیف دسته بندی کند.از عنصر <TableRow> برای ایجاد یک ردیف در جدول استفاده می کنیم.هر ردیف می تواند یک یا چند view داشته باشد.هر view که در یک ردیف قرار می دهید,به شکل یک سلول در می آید.اندازه ی عرض هر ستون به اندازه ی بزرگترین سلول موجود در آن ستون است.فرض کنید فایل main.xml به صورت زیر است.

 

<?xml version=”1.0” encoding=”utf-8”?>
<TableLayout
xmlns:android=”http://schemas.android.com/apk/res/android”
android:layout_height=”fill_parent”
android:layout_width=”fill_parent”
>
<TableRow>
<TextView
android:text=”User Name:”
android:width =”120px”
/>
<EditText
android:id=”@+id/txtUserName”
android:width=”200px” />
</TableRow>
<TableRow>
<TextView
android:text=”Password:”
/>
<EditText
android:id=”@+id/txtPassword”
android:password=”true”
/>
</TableRow>
<TableRow>
<TextView />
<CheckBox android:id=”@+id/chkRememberPassword”
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=”Remember Password”
/>
</TableRow>
<TableRow>
<Button
android:id=”@+id/buttonSignIn”
android:text=”Log In” />
</TableRow>
</TableLayout>

توجه داشته باشید که در مثال فوق,دو ستون و 4 ردیف در TableLayout قرار دارد.سلولی که در زیر TextView پسوورد است به وسیله ی یک عنصر خالی <TextView/> ایجاد شده است.اگر به این شکل عمل نکنید checkBox در زیر TextView قرار میگیرد.

RelativeLayout

به شما این قابلیت را می دهد که چینش اجزا, وابسته به چینش یکیدیگر باشند.

فرض کنید که فایل main.xml به صورت زیر است:

 

<?xml version=”1.0” encoding=”utf-8”?>
<RelativeLayout
android:id=”@+id/RLayout”
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
xmlns:android=”http://schemas.android.com/apk/res/android”
>
<TextView
android:id=”@+id/lblComments”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”Comments”
android:layout_alignParentTop=”true”
android:layout_alignParentLeft=”true”
/>
<EditText
android:id=”@+id/txtComments”
android:layout_width=”fill_parent”
android:layout_height=”170px”
android:textSize=”18sp”
android:layout_alignLeft=”@+id/lblComments”
android:layout_below=”@+id/lblComments”
android:layout_centerHorizontal=”true”
/>
<Button
android:id=”@+id/btnSave”
android:layout_width=”125px”
android:layout_height=”wrap_content”
android:text=”Save”
android:layout_below=”@+id/txtComments”
android:layout_alignRight=”@+id/txtComments”
/>
<Button
android:id=”@+id/btnCancel”
android:layout_width=”124px”
android:layout_height=”wrap_content”
android:text=”Cancel”
android:layout_below=”@+id/txtComments”
android:layout_alignLeft=”@+id/txtComments”
/>
</RelativeLayout>

توجه داشته باشید view که در RelativeLayout قرار دارد خصوصیاتی را شامل می شود که به شما اجازه می دهد محل قرارگیری آن را با view دیگری تنظیم کنید.این خصوصیات شامل موارد زیر است:

  • layout_alignParentTop
  • layout_alignParentLeft
  • layout_alignLeft
  • layout_alignRight
  • layout_below
  • layout_centerHorizontal

مقداری که برای هر کدام از این خصوصیات می توان در نظر گرفت,ID آن view است که می خواهیم به آن اشاره شود.

FrameLayout

محلی برای قرار دادن تنها یک view می باشد.viewهایی که به FrameLayout اضافه می شوند,همیشه به سمت چپ و بالای صفحه شما می چسبند.فرض کنید فایل main.xml به صورت زیر باشد.

 

<?xml version=”1.0” encoding=”utf-8”?>
<RelativeLayout
android:id=”@+id/RLayout”
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
xmlns:android=”http://schemas.android.com/apk/res/android”
>
<TextView
android:id=”@+id/lblComments”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”This is my lovely dog, Ookii”
android:layout_alignParentTop=”true”
android:layout_alignParentLeft=”true”
/>
<FrameLayout
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_alignLeft=”@+id/lblComments”
android:layout_below=”@+id/lblComments”
android:layout_centerHorizontal=”true”
>
<ImageView
android:src = “@drawable/ookii”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
/>
</FrameLayout>
</RelativeLayout>

در این کدها یک FreamLayout در میان یک RelativeLayout وجود دارد.درون FrameLayout یک ImageView قرار دارد.

اگر یک view دیگر در FrameLayout اضافه کنید(مثل یک Button) ,بر روی view قبلی قرار می گیرد.

 

<?xml version=”1.0” encoding=”utf-8”?>
<RelativeLayout
android:id=”@+id/RLayout”
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
xmlns:android=”http://schemas.android.com/apk/res/android”
>
<TextView
android:id=”@+id/lblComments”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”This is my lovely dog, Ookii”
android:layout_alignParentTop=”true”
android:layout_alignParentLeft=”true”
/>
<FrameLayout
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_alignLeft=”@+id/lblComments”
android:layout_below=”@+id/lblComments”
android:layout_centerHorizontal=”true”
>
<ImageView
android:src = “@drawable/ookii”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
/>
<Button
android:layout_width=”124dp”
android:layout_height=”wrap_content”
android:text=”Print Picture”
/>
</FrameLayout>
</RelativeLayout>

می توانید چندین view به FrameLayout بیافزایید,اما هر کدام از آنها بر روی قبلی قرار می گیرند.با این روش می توانید یک انیمیشن ایجاد کنید و در هر لحظه یکی از view ها را نمایش دهید.

ScrollView

یک نوع بخصوصی از FrameLayout است.چون به کاربر اجازه می دهد تا میان لیستی از ابزار های نمایش که تمام فضای فیزیکی صفحه را اشغال کرده اند,پیمایش کند.ScrollView تنها می تواندیک فرزند view یا ViewGroup داشته باشد که معمولاً از LineearLayout استفاده می شود.

در زیر یک ScrollView را در فایل main.xml نشان داده ایم که حاوی یک LinearLayout است کع آن هم شامل Button و EditText می باشد:

 

<?xml version=”1.0” encoding=”utf-8”?>
<ScrollView
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
xmlns:android=”http://schemas.android.com/apk/res/android”
>
<LinearLayout
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:orientation=”vertical”
>
<Button
android:id=”@+id/button1”
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=”Button 1”
/>
<Button
android:id=”@+id/button2”
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=”Button 2”
/>
<Button
android:id=”@+id/button3”
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=”Button 3”
/>
<EditText
android:id=”@+id/txt”
android:layout_width=”fill_parent”
android:layout_height=”300px”
/>
<Button
android:id=”@+id/button4”
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=”Button 4”
/>
<Button
android:id=”@+id/button5”
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=”Button 5”
/>
</LinearLayout>
</ScrollView>

از آنجا که EditText به صورت خودکار فوکوس دارد,کل اکتیویتی را پر می کند.برای جلوگیری از فوکوس اتوماتیک آن خصوصیات زیر را به <LinearLayout> اضافه کنید:

focusable

<LinearLayout
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:orientation=”vertical”
android:focusable="true"
android:focusableInTouchMode="true"

>

 در مواقعی نیاز است تا EditText به صورت خودکار انتخاب شود.اما شما نیازی نمی بینید تا صفحه کلید به صورت خودکار نمایش داده شود.برای جلوگیری از نمایش صفحه کلید خصوصیات زیر را به عنصر <activity> در فایل AndroidManifest.xml اضافه کنید:

 

<activity 
android:label=”@string/app_name”
android:name =".LayoutsActivity"
android:windowSoftInputMode="stateHidden" >
<intent-filter>
<action android:name=”android.intent.action.MAIN” />
<category android:name=”android.intent.category.LAUNCHER” />
</intent-filter>
</activity>

تطبیق با جهت صفحه نمایش

یکی از ویژگی های کلیدی گوشی های هوشمند,قابلیت چرخش گوشی در جهات افقی و عمودی است.اندروید هم جهت افقی و هم عمودی را پشتیبانی می کند.در حالت عادی وقتی که جهت گوشی را عوض می کنید,اکتیویتی کنونی سعی می کند با توجه به جهت چرخش رابط کاربری را دوباره ترسیم کند.این عمل به این دلیل اتفاق می افتد که در هنگام تغییر جهت گوشی رویداد ()onCreate دوباره فراخوانی می گردد.

در این حالت تمامی عناصر به جای اصلیشان بر میگردند .دقت کنید که در حالت افقی فضای زیادی در سمت راست بلا استفاده مانده است.علاوه بر آن در حالت افقی ممکن است چند view به دلیل تعدد ابزارهای نمایش و قرار گرفتن در پایین صفحه از نظر پنهان می باشند.معمولاً دو روش برای کنترل تغییر جهت وجود دارد:

  • Anchoring (مهار کردن):بدین معنا که view را به چهار طرف صفحه متصل می کنیم.این راحت ترین راه ممکن است.وقتی که جهت عوض شود,دوباره رابط کاربری شما به چهار طرف متصل می گردد.
  • Resizing and repositioning (تغییر اندازه و چینش دوباره): گرچه روش مهار کردن راحت ترین روش برای اطمینان از نمایش رابط کاربری در جهات مختلف است,اما تکنیک برتر تغییر اندازه تمامی ابزارهای نمایش و چینش دوباره آنها بر اساس جهت کنونی می باشد.

روش مهار کردن ابزارهای نمایش

با استفاده از RelativeLayout به راحتی می توان از این روش بهره گرفت.در زیر یک فایل main.xml در اختیار داریم که حاوی پنج دکمه است که درون عنصر <RelativeLayout> قرار دارند:

 

<?xml version=”1.0” encoding=”utf-8”?>
<RelativeLayout
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
xmlns:android=”http://schemas.android.com/apk/res/android”
>
<Button
android:id=”@+id/button1”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”Top Left Button”
android:layout_alignParentLeft=”true”
android:layout_alignParentTop=”true”
/>
<Button
android:id=”@+id/button2”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”Top Right Button”
android:layout_alignParentTop=”true”
android:layout_alignParentRight=”true”
/>
<Button
android:id=”@+id/button3”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”Bottom Left Button”
android:layout_alignParentLeft=”true”
android:layout_alignParentBottom=”true”
/>
<Button
android:id=”@+id/button4”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”Bottom Right Button”
android:layout_alignParentRight=”true”
android:layout_alignParentBottom=”true”
/>
<Button
android:id=”@+id/button5”
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=”Middle Button”
android:layout_centerVertical=”true”
android:layout_centerHorizontal=”true”
/>
</RelativeLayout>

به بخش زیر توجه کنید.دکمه ها از هر نوعی که باشند دارای خصوصیات زیر هستند:

  • view -- layout_alignParentLeft را در سمت چپ والد می چیند.
  • view -- layout_alignParentRight را در سمت راست والد می چیند.
  • view -- layout_alignParentTop را در بالای والد می چیند.
  • view -- layout_alignParentBottom را در پایین والد می چیند.
  • view -- layout_centerVertical را به صورت عمودی در وسط والد می چیند.
  • view -- layout_centerHorizontal را به صورت افقی در وسط والد می چیند.

روش تغییر اندازه و چینش مجدد

به جز روش قبلی یعنی مهار کردن ابزارهای نمایش,یک راه حل راحتتری برای سفارشی سازی رابط کاربری با توجه به جهت چرخش دستگاه,ایجاد فولدرهای مختلف در res/layout و ایجاد فایل های XML به ازای هر کدام از جهات افقی یا عمودی می باشد.برای پشتیبانی حالت افقی,باید یک فولدر در res به نام layout-land ساخته شود.معمولاً فایل main.xml که درون فولدر layout قرار دارد,حاوی رابط کاربری برای حالت عمودی است.اما فایل main.xml که در فولدر layout-land  قرار گرفته است حاوی رابط کاربری برای حالت افقی می باشد.

کدهای زیر نمایش دهنده ی محتوای فایل main.xml در فولدر layout می باشد:

 

<?xml version=”1.0” encoding=”utf-8”?>
<RelativeLayout
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
xmlns:android=”http://schemas.android.com/apk/res/android”
>
<Button
android:id=”@+id/button1”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”Top Left Button”
android:layout_alignParentLeft=”true”
android:layout_alignParentTop=”true”
/>
<Button
android:id=”@+id/button2”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”Top Right Button”
android:layout_alignParentTop=”true”
android:layout_alignParentRight=”true”
/>
<Button
android:id=”@+id/button3”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”Bottom Left Button”
android:layout_alignParentLeft=”true”
android:layout_alignParentBottom=”true”
/>
<Button
android:id=”@+id/button4”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”Bottom Right Button”
android:layout_alignParentRight=”true”
android:layout_alignParentBottom=”true”
/>
<Button
android:id=”@+id/button5”
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=”Middle Button”
android:layout_centerVertical=”true”
android:layout_centerHorizontal=”true”
/>
</RelativeLayout>

کدهای زیر نمایش دهنده ی محتوای فایل main.xml در فولدر layout-land می باشد.کدهای زیر که به صورت پر رنگ تر هستند آنهایی هستند که در بخش افقی اضافه شده اند:

 

<?xml version=”1.0” encoding=”utf-8”?>
<RelativeLayout
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
xmlns:android=”http://schemas.android.com/apk/res/android”
>
<Button
android:id=”@+id/button1”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”Top Left Button”
android:layout_alignParentLeft=”true”
android:layout_alignParentTop=”true”
/>
<Button
android:id=”@+id/button2”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”Top Right Button”
android:layout_alignParentTop=”true”
android:layout_alignParentRight=”true”
/>
<Button
android:id=”@+id/button3”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”Bottom Left Button”
android:layout_alignParentLeft=”true”
android:layout_alignParentBottom=”true”
/>
<Button
android:id=”@+id/button4”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”Bottom Right Button”
android:layout_alignParentRight=”true”
android:layout_alignParentBottom=”true”
/>
<Button
android:id=”@+id/button5”
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=”Middle Button”
android:layout_centerVertical=”true”
android:layout_centerHorizontal=”true”
/>
<Button
android:id=”@+id/button6”
android:layout_width=”180px”
android:layout_height=”wrap_content”
android:text=”Top Middle Button”
android:layout_centerVertical=”true”
android:layout_centerHorizontal=”true”
android:layout_alignParentTop=”true”
/>
<Button
android:id=”@+id/button7”
android:layout_width=”180px”
android:layout_height=”wrap_content”
android:text=”Bottom Middle Button”
android:layout_centerVertical=”true”
android:layout_centerHorizontal=”true”
android:layout_alignParentBottom=”true”
/>
</RelativeLayout>

با استفاده از این روش هرگاه چرخشی به وقوع بپیوندد,اندروید به صورت اتوماتیک XML مربوطه را بارگذاری می کند.

مدیریت تغییر و چرخش صفحه نمایش

تا اینجا متوجه شده اید که چگونه برنامه خود را با جهت های مختلف سازگار کنید.از این پس وضعیت های مختلفی که برای اکتیویتی در هنگام چرخش رخ خواهد داد را بررسی می کنیم.

در تمرین زیر رفتار یک اکتیویتی را در هنگام چرخش یک دستگاه را بررسی می کنیم.

1.یک پروژه ی جدید  با نام  Orientations ایجاد کنید.

2.فایل main.xml را به صورت زیر تغییر دهید:

 

<?xml version=”1.0” encoding=”utf-8”?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
android:orientation=”vertical”
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
>
<EditText
android:id=”@+id/txtField1”
android:layout_width=”fill_parent”
android:layout_height=”wrap_content” />
<EditText
android:layout_width=”fill_parent”
android:layout_height=”wrap_content” />
</LinearLayout>

3.فایل MainActivity.java را به صورت زیر تغییر دهید:

 

package com.PRG.Orientations;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d(“StateInfo”, “onCreate”);
}
@Override
public void onStart() {
Log.d(“StateInfo”, “onStart”);
super.onStart();
}
@Override
public void onResume() {
Log.d(“StateInfo”, “onResume”);
super.onResume();
}
@Override
public void onPause() {
Log.d(“StateInfo”, “onPause”);
super.onPause();
}
@Override
public void onStop() {
Log.d(“StateInfo”, “onStop”);
super.onStop();
}
@Override
public void onDestroy() {
Log.d(“StateInfo”, “onDestroy”);
super.onDestroy();
}
@Override
public void onRestart() {
Log.d(“StateInfo”, “onRestart”);
super.onRestart();
}
}

4.برنامه را اجرا کنید.

5.با استفاده از کلیدهای Ctrl + F11 جهت شبیه ساز را عوض کنید.

6.خروجی پنجره ی LogCat را مشاهده کنید.برای این کار باید در ایکلیپس به حالت Bebug prespective بروید.که باید چیزی شبیه زیر باشد:

 

01-05 13:32:30.266: DEBUG/StateInfo(5477): onCreate
01-05 13:32:30.296: DEBUG/StateInfo(5477): onStart
01-05 13:32:30.296: DEBUG/StateInfo(5477): onResume
...
01-05 13:35:20.106: DEBUG/StateInfo(5477): onPause
01-05 13:35:20.106: DEBUG/StateInfo(5477): onStop
01-05 13:35:20.106: DEBUG/StateInfo(5477): onDestroy
01-05 13:35:20.246: DEBUG/StateInfo(5477): onCreate
01-05 13:35:20.256: DEBUG/StateInfo(5477): onStart
01-05 13:35:20.256: DEBUG/StateInfo(5477): onResume

روش کار

از نوشته های این پنجره ی LogCat می توان به این نتیجه رسید که در هنگام چرخش دستگاه,اکتیویتی نابود می شود:


01-05 13:35:20.106: DEBUG/StateInfo(5477): onPause
01-05 13:35:20.106: DEBUG/StateInfo(5477): onStop
01-05 13:35:20.106: DEBUG/StateInfo(5477): onDestroyااا

و در ایجاد دوباره ی آن به صورت زیر می شود:

 

01-05 13:35:20.246: DEBUG/StateInfo(5477): onCreate
01-05 13:35:20.256: DEBUG/StateInfo(5477): onStart
01-05 13:35:20.256: DEBUG/StateInfo(5477): onResume

درک این رفتار اندروید بسیار مهم است.چون شما باید این موضوع را به خوبی بدانید تا بتوانید وضعیت اکتیویتی را قبل از چرخش دستگاه حفظ کنید.به عنوان مثال فرض کنید که اکتیویتی شما دارای مقادیری است که برای انجام محاسبات به آن احتیاج دارید.برای حفظ وضعیت اکتیویتی باید در هنگام رویداد ()onPause هر کاری را که لازم است انجام دهید.چرا که در هنگام چرخش اولین رویدادی که رخ می دهد این رویداد است.نکته ی قابل توجه دیگر این است که تنها ابزارهای نمایشی که در خصوصیت android:id آنها نام گذاری صورت گرفته است,بعد از چرخش وضعیت قبلی خود را حفظ خواهند کرد.فرض کنید کاربر در حال وارد کردن متنی در یک EditText است, ناگهان یک چرخش صورت می گیرد.به محض اینکه این رویداد رخ دهد , آن EditText به صورت اتوماتیک در هنگام دوباره ایجاد شدن اکتیویتی,حاوی متنی است که تا کنون وارد شده و کاربر به راحتی به کار خود ادامه می دهد.اما اگر نام گذاری به واسطه ی android:id صورت نگیرد, اکتیویتی نمی تواند محتوای کنونی را به حالت قبل از چرخش باز گرداند.

تداوم وضعیت اطلاعات هنگام تغییرات اساسی

تا اینجای کار متوجه شدید که در هنگام چرخش دستگاه,اکتیویتی نابود شده و دوباره ایجاد می شود.این نکته را نیز می دانید که ایجاد دوباره رابط کاربری تضمینی برای حفظ حالت قبلی خود ندارد.وقتی یک اکتیویتی نابود می شود حداقل یکی از متدهای زیر اجرا می شود:

  • ()onPause -- این متد همیشه هنگامی که اکتیویتی نابود می گردد و یا به پس زمینه می رود,اجرا می گردد.
  • ()onSaveInstanceState -- این متد هم مثل متد بالایی در هنگام نابودی اکتیویتی و یا در هنگام رفتن اکتیویتی به پس زمینه اجرا می گردد.اما بر  خلاف متد ()onPause این متد در هنگام تخلیه ی اکتیویتی از stack, اجرا نمی گردد.مثل زمانی که کاربر کلید Back دستگاه را فشار می دهد.چون نیازی به بازیابی وضعیت نمی باشد.

به طور کلی برای حفظ وضعیت اکتیویتی,همیشه باید متد ()onPause را پیاده سازی کرد,و بعد نسبت به بازیابی آن از روش هایی مثل استفاده از بانک اطلاعاتی, ذخیره در حافظه درونی یا بیرونی و ... استفاده کرد.

اگر راه آسان حفظ اطلاعات مطلوب شماست و تنها می خواهید هنگامی که اکتیویتی مجدداً ایجاد شد,اطلاعات حفظ شده بازیابی گردد.مثل زمانی که گوشی چرخش دارد.بهترین کار پیاده سازی متد ()onSaveInstanceState است.این متد یک شئ Bundle را به عنوان آرگومان ارائه می دهد که به وسیله ی آن می توانید وضعیت اکتیویتی را حفظ کنید.مثال زیر نحوه ی ذخیره یک رشته به نام ID را درون شئ Bundle در متد()onsaveInstanceState نشان می دهد:

 

@Override
public void onSaveInstanceState(Bundle outState) {
//---save whatever you need to persist---
outState.putString(“ID”, “1234567890”);
super.onSaveInstanceState(outState);
}

وقتی که یک اکتیویتی دوباره ایجاد شد,اولین متدی که اجرا می شود متد ()onCreate است, به دنبال آن متد ()onRestoreInstanceState نیز اجرا می گردد که باعث می شود تا حالت قبلی که با استفاده از متد ()onSaveInstanceState که به واسطه ی شئ Bundle به عنوان آرگومان ذخیره شده است,بازیابی گردد:

 

@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
//---retrieve the information persisted earlier---
String ID = savedInstanceState.getString(“ID”);
}

 این در حالی است که از متد ()onSaveInstanceState نیز برای حفظ اطلاعات استفاده می کنید.توجه داشته باشید که تنها میتوان اطلاعات را در شئ Bundle ذخیره نمود.اگر به دنبال ذخیره ی اطلاعات بیشتر و پیچیده تری هستید,این روش راه حل مناسبی نیست.راه دیگری که می توان از آن استفاده کرد,بکار بردن متد()onRetainNonConfigurationInstance است.این متد هم هنگامی اجرا می شود که اکتیویتی به دلیل رویدادها و تغییرات اساسی در حال نابودی باشد مثل وقتی که جهت دستگاه عوض شود می توان با برگشت داده از طریق این متد,داده مورد نظر را حفظ کرد.مثل کد زیر:

 

@Override
public Object onRetainNonConfigurationInstance() {
//---save whatever you want here; it takes in an Object type---
return(“Some text to preserve”);
}

 وقتی جهت تصویر تغییر می کند ,این تغییر را یک تغییر اساسی می نامند.تغییرات اساسی باعث می شوند که اکتیویتی نابود گردد.توجه داشته باشید که  خروجی این متد از نوع Object است که به شما این اجازه را می دهد از هر نوع داده ی مورد نظر استفاده کنید.برای استخراج اطلاعات ذخیره شده میتوانید در متد ()onCreate این کار را با استفاده از متد ()getLastNonConfigurationInstance انجام دهید:

 

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d(“StateInfo”, “onCreate”);
String str = (String) getLastNonConfigurationInstance();
}

یکی از استفاده های بجا از متدهای ()onRetainNonConfigurationInstance و ()getLastNonConfigurationInstnce زمانی است که می خواهید اطلاعاتی را به صورت لحظه ای حفظ کنید.مثل زمانی که در حال دانلود اطلاعات از یک وب سرویس هستید و در همان لحظه یک چرخش ایجاد می گردد.در این حالت استفاده از متدهای بالا بسیار کاربردی و با کارایی بیشتر به نظر می رسد.

تشخیص تغییر جهت

در بعضی مواقع نیاز است تا در زمان اجرا برنامه وضعیت جهت دستگاه را بدانیم.برای این کار از کلاس WindowManager استفاده می کنیم.در کد زیر نشان می دهیم که چگونه وضعیت دستگاه را در زمان اجرا تشخیص دهیم:

 

import android.util.Log;
import android.view.Display;
import android.view.WindowManager;
//...
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//---get the current display info---
WindowManager wm = getWindowManager();
Display d = wm.getDefaultDisplay();
if (d.getWidth() > d.getHeight())
{
//---landscape mode---
Log.d(“Orientation”, “Landscape mode”);
}
else
{
//---portrait mode---
Log.d(“Orientation”, “Portrait mode”);
}
}

متد ()getDefaultDisplay یک شئ از نوع Display که همان صفحه نمایش دستگاه است را باز می گرداند.سپس می توانید طول و عرض آن را گرفته و به وسیله ی آنها جهت دستگاه را پیدا کنید.

کنترل جهت یک اکتیویتی

 گاهی اوقات ممکن است تمایل داشته باشید که اکتیویتی شما فقط در یک جهت نمایش داده شود.برای مثال یک بازی معمولاً در حالت افقی نمایش داده می شود.برای این کار می توانید از متد ()setRequestOrientation کلاس Activity استفاده کنید:

 

import android.content.pm.ActivityInfo;
public class MainActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//---change to landscape mode---
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}

برای نمایش در حالت عمودی از ثابت ActivityInfo.SCREEN_ORIENTATION_PORTRAT استفاده کنید.

 

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

به غیر از متد ()setRequestOrientation می توانید از خصوصیت android:screenOrientation عنصر<activity> در فایل AndroidManifest نیز مانند مثال زیر برای تعیید جهت صفحه نمایش استفاده کنید:


<?xml version=”1.0” encoding=”utf-8”?>
<manifest xmlns:android=”http://schemas.android.com/apk/res/android”
package=”net.learn2develop.Orientations”
android:versionCode=”1”
android:versionName=”1.0”>
<application android:icon=”@drawable/icon” android:label=”@string/app_name”>
<activity android:name=”.MainActivity”
android:label=”@string/app_name”
android:screenOrientation=”landscape” >
<intent-filter>
<action android:name=”android.intent.action.MAIN” />
<category android:name=”android.intent.category.LAUNCHER” />
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion=”9” />
</manifest>

کد بالا اکتیویتی را در یک جهت مشخص نمایش می دهد که در اینجا به صورت افقی است,و از نابود شدن اکتیویتی جلوگیری میکند.این به این معنا است که اکتیویتی با چرخش دستگاه نابود نشده و متد ()onCreate دوباره فراخوانی نمی گردد.در زیر دو مقدار دیگر که می توانید از آنها در خصوصیت android:screenOrientation استفاده کنید را مشاهده می کنید:

  • portrait --حالت عمودی
  • Sensor --بر اساس سنسور شتاب سنج(پیش فرض)
تمامی محصولات و خدمات این وبسایت، حسب مورد دارای مجوزهای لازم از مراجع مربوطه می‌باشند و فعالیت‌های این سایت تابع قوانین و مقررات جمهوری اسلامی ایران است.
logo-samandehiمجوز نشر دیجیتال از وزرات فرهنگ و ارشاد اسلامیپرداخت آنلاین -  بانک ملتمعرفی بیاموز در شبکه سهپرداخت آنلاین - بانک اقتصاد نوینپرداخت آنلاین - بانک سامان