Name of the blog

Short description of the blog

نسبت به مجوزهای برنامه‌های کاربردی اندروید بی تفاوت نباشید

نسبت به مجوزهای برنامه‌های کاربردی اندروید بی تفاوت نباشید

توسعه‌دهندگان برنامه‌های کاربردی با توجه به عدم آگاهی و بی‌توجهی برخی کاربران، مجوزهایی را از آنها می‌خواهند که راه را برای نفوذ به دستگاه‌های اندرویدی باز می‌کند، بنابراین با توجه به تولید انبوه برنامه‌های کاربردی سیستم‌عامل اندرویدی، باید درباره خطر احتمالی برنامه‌هایی که تهدیدی را برای کاربران دستگاه‌های اندرویدی ایجاد می‌کنند، اطلاع‌رسانی شود

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

 

شاید رد کردن یا اختیار دادن به مجوزهای درخواستی برنامه‌های کاربردی در حال نصب، ساده‌ترین کاری باشد که یک کاربر می‌تواند انجام دهد؛ اما نکته مهم این است که تا چه اندازه می‌توان تفاوت بین حفاظت و تأمین امنیت داده کاربر و نیز در اختیار قرار دادن تمام دارایی‌های شخص در دست توسعه‌دهنده برنامه کاربردی را درک کرد.

 

محدوده مجوزها برای تعامل برنامه کاربردی از اجازه دسترسی به بخش ویژه‌ای از سخت‌افزار دستگاه (به‌عنوان‌ مثال فلش دوربین عکاسی) آغاز می‌شود و تا دسترسی به لیست مخاطبان کاربر ادامه می‌یابد. کاربر نیز باید با تمام مجوزهای لیست شده قبل از نصب برنامه کاربردی موافقت کند.

 

نوتو برنامه جدید گوگل

 

گوگل که از دست‌اندازی به هیچ حوزه‌ای در عرصه فناوری غفلت نمی‌کند، این بار برنامه‌ای به نام نوتو طراحی کرده که با استفاده از آن می‌توان به تمامی زبان‌های دنیا مطلب تایپ کرد.

 

نوتو یک برنامه جامع حاوی فونت‌های نگارش به صدها زبان است که می‌تواند تمامی زبان‌های دنیا و حتی زبان‌هایی که رایانه شما آنها را تشخیص نمی‌دهد را شناسایی کند.

 

با استفاده از این برنامه می‌توان متون مختلف را به زبان‌های اصلی نوشت و به اشتراک گذاشت. خانواده فونت‌های این برنامه بیش از ۸۰۰ زبان و ۱۰۰ نوع دست‌خط نوشتاری را پوشش می‌دهد.

 

گوگل پنج سال برای تکمیل این طرح وقت گذاشته و حالا یکی از بزرگترین پروژه‌های نگارشی دنیا را به صورت متن باز تکمیل کرده و به سرانجام رسانده است.

 

باب جونگ مدیر واحد بین‌المللی‌سازی گوگل در این مورد می‌گوید: هدف ما از طراحی نوتو ایجاد فونت‌های مناسب برای محصولاتمان بوده است، اما با این کار می‌توان اطلاعات را هم زنده نگهداشت. زیرا بخشی از اطلاعات به زبان‌های کمتر مورد استفاده جهان یا حتی به زبان‌های کاملا دانشگاهی یا مرده تولید می‌شوند. ما فکر می‌کنیم بسیار مهم است که این زبان‌ها را حفظ کنیم و با استفاده از نوتو می‌توان این منابع فرهنگی را حفظ کرد.

 

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

5G چیست؟

 

 

 

اصطلاح  5Gبه نسل بعدی شبکه تلفن همراه دلالت می‌کند. از زمانی که شبکه4G گستره زیادی از نواحی را پوشش می‌داد، شاهد پیدایش شبکه‌های LTE، LTE پیشرفته و XLTE اوپراتور ورایزن بوده‌ایم که پهنای باند وسیعی را دارا هستند.

 

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

 

دانستن تفاوت‌های بین این شبکه‌ها ضروری است، چراکه عملکرد گوشی شما بسیار به کانکشنی که انتخاب کرده‌اید، بستگی دارد و اهمیت آن فراتر از علامتی است که به‌عنوان نماد برقراری اتصال در بالای سمت راست صفحه‌نمایش گوشی شما ظاهر می‌شود.

 

مهاجرت از 3G به 4G باعث ایجاد یک جهش بزرگ در راستای بهبود سرعت دانلود شد. درصورتی‌که قبل از آن استفاده از خدمات آنلاین سرویس‌هایی مثل Netflix با 3G  تقریباً غیرممکن بود. این ‌یکی از مواردی است که لزوم مهاجرت به 4G را برای کاربران مطرح می‌کند.اما امتیاز فناوری جدید  5Gتنها محدود به‌سرعت فوق‌العاده‌اش نیست، این فناوری به حل یکی از بزرگ‌ترین مشکلات امروز ما یعنی اتصال به یک کانکشن مورد اعتماد و سریع،‌ خواهد پرداخت. مهم نیست که کاربر نزدیک به پنجره بوده و داخل یا خارج ساختمان باشد، حتی اینکه در یک زیرزمین هم دفن شده باشد اهمیتی ندارد! اولین هدف 5Gاین است که کاربر در همه شرایط به اینترنت دسترسی داشته باشد.

 

یکی از دلایلی که به چنین کانکشن قدرتمندی نیاز داریم، این است که ساپورت 5G تنها محدود به اسمارت‌فون‌ها نیست و قابلیت پشتیبانی از دیگر ابزارها نظیر ساعت‌های مچی هوشمند، گجت‌های تناسب‌اندام و ترموستات‌های هوشمند خانگی را دارد

 

fdgdfgdf

پیاده سازی یک کنترل اختصاصی (Custom control)

در این مبحث، شما یک کنترل جهت امتیاز دهی (rating control) برای برنامه ی FoodTracker پیاده سازی خواهید کرد. در پایان، برنامه ی شما ظاهری مشابه نمونه زیر خواهد داشت:

آنچه خواهید آموخت

·         ایجاد المان های UI اختصاصی به همراه فایل های source code مرتبط. متصل کردن المان های UI در storyboard به کد آن ها.

·         تعریف کلاس اختصاصی.

·         پیاده سازی یک متد initializer (مقداردهنده ی اولیه) داخل کلاس اختصاصی مورد نظر.

·         استفاده از کلاس UIView به عنوان یک ظرف.

·         نحوه ی به نمایش گذاشتن محتوای view ها برای کاربر با کدنویسی (programmatically).

تعریف یک View اختصاصی

برای اعطا کردن قابلیت امتیاز دهی به غذاهای موجود در برنامه به کاربر، لازم است یک control تعریف کنید که تعدادی ستاره نمایش داده و کاربر برای نظر دادن درباره ی غذا باید این ستاره ها را پر کند. روش های مختلفی برای پیاده سازی این قابلیت وجود دارد. در آموزش حاضر از این روش استفاده خواهید کرد: یک view اختصاصی با کد تعریف کرده و سپس آن را در storyboard خود مورد استفاده قرار خواهید داد.

در زیر نمایی از کنترلی که جهت نمایش و تخصیص امتیاز به غذا پیاده سازی خواهید کرد را مشاهده می کنید:

کنترل نام برده به کاربران این امکان را می دهد تا بر اساس میزان محبوبیت غذا، به آن ستاره تخصیص دهند. همان طور که می بینید این کنترل در کل 5 ستاره نمایش می دهد که پنجمین ستاره طبیعتا نشانگر بالاترین امتیاز برای آن غذا می باشد. زمانی که کاربر بر روی یک ستاره ضربه می زند، تمامی ستاره های منتهی به آن (از جمله خود ستاره ی انتخاب شده) از سمت چپ پر می شوند.

برای اقدام به طراحی ظاهر (UI)، قابلیت تعامل با کاربر و رفتار این کنترل، بایستی ابتدا یک کلاس فرزند view با پیاده سازی اختصاصی از UIView ایجاد کنید (یک custom view subclass از کلاس پایه UIView ایجاد نمایید.)

جهت ایجاد یک کلاس فرزند از UIView، مراحل زیر را گام به گام دنبال نمایید:

1.      این مسیر را طی کنید: File > New > File یا Command-N را فشار دهید.

2.      یک کادر محاوره ای نمایان می شود. در سمت چپ آن، گزینه ی IOS را انتخاب نمایید.

3.      گزینه ی Cocoa Touch Class را انتخاب نموده و بر روی Next کلیک کنید.

4.      داخل فیلد Class، عبارت RatingControl را وارد نمایید.

5.      حال گزینه ی UIView را از فیلد Subclass of انتخاب نمایید.

6.      زبان برنامه نویسی پروژه را بر روی Swift تنظیم نمایید.

7.      بر روی دکمه ی Next کلیک کنید.

محل ذخیره ی فایل به صورت پیش فرض بر روی دایرکتوری پروژه ی جاری شما تنظیم می شود.

گزینه ی Group به صورت پیش فرض بر روی اسم برنامه ی فعلی، FoodTracker تنظیم می شود.

در بخش Targets، می بینید که برنامه ی شما انتخاب شده اما تست های مربوط به آن انتخاب نشده اند.

8.      لازم نیست تنظیمات پیش فرض را دستکاری نمایید. کافی است بر روی Create کلیک کرده تا فایل مورد نظر ایجاد گردد.  

Xcode یک فایل جدید، حاوی RatingControl class: RatingControl.swift ایجاد می کند. RatingControl یک کلاس اختصاصی view، ارث بری شده از کلاس پایه ی UIView است (منظور از کلاس فرزند اختصاصی، کلاسی است که متدهای کلاس پایه در آن بازنویسی شده باشند).

9.      در فایل RatingControl.swift، تمامی comment هایی که همراه با قالب آماده (template) و پیاده سازی الگو (template implementation) ارائه می شوند را حذف نمایید.

در حال حاضر پیاده سازی کلاس بایستی مشابه زیر باشد:

import UIKit

class RatingControl: UIView {

}

View معمولا به دو روش زیر ایجاد می شود: روش اول عبارت است مقدار دهی اولیه ی یک view با یک فریم که به شما امکان می دهد view را به صورت دستی به UI اضافه کنید و روش دوم، عبارت است از واگذار کردن بارگذاری view به storyboard. برای هر یک از روش های نام برده یک متد initializer اختصاصی وجود دارد: به منظور مقداردهی اولیه و ایجاد یک فریم برای view از متد init(frame:) و برای روش دوم، محول کردن بارگذاری view به storyboard، از متد init?(coder:) استفاده می کنیم. یادآور می شویم که initializer متدی است که یک نمونه از روی کلاس جاری می سازد، property های آن کلاس را مقداردهی اولیه نموده و در صورت لزوم سایر تنظیمات آغازین را انجام می دهد.

در آموزش حاضر، از روش دوم اقدام به ایجاد view خواهید نمود (در storyboard با view خود کار خواهید کرد)، از این رو لازم است ابتدا (پیاده سازی) متد init?(coder:) کلاس والد view را override (بازنویسی) نمایید.

به منظور بازنویسی پیاده سازی متد initializer، مراحل زیر را گام به گام دنبال نمایید:

1.      داخل فایل RatingControl.swift، در زیر خط تعریف کلاس، این comment را درج نمایید:

1.       // MARK: Initialization

2.      حال در زیر این comment، ابتدا واژه ی init را تایپ کنید.

خواهید دید که ابزار پیشبینی و تکمیل کد (code completion) محیط کاری Xcode نمایان می شود.

3.      سومین متد را در لیستی که پدیدار می شود (init?(coder:)) انتخاب کرده و سپس کلید Return را فشار دهید.

init?(coder aDecoder: NSCoder) {

}

Xcode خود اسکلت (کد لازم) متد را برای شما درج می کند.

4.      یک پیغام خطا با آیکون قرمز رنگ به نمایش در می آید. بر روی Fix-it کلیک کرده تا Xcode کلیدواژه ی required را به متد initializer اضافه کند.

 

required init?(coder aDecoder: NSCoder) {

}

تمامی کلاس های ارث بری شده از UIView (کلاس های فرزند آن) که متد initializer را پیاده سازی می کنند، می بایست متد init?(coder:) را نیز در بدنه ی خود داشته و پیاده سازی کنند. کامپایلر زبان Swift به این امر واقف بوده و راه حل خود (جهت ویرایش کد) را در قالب fix-it برای شما ارائه می کند. Fix-it ها راه حل هایی هستند که کامپایلر در جواب خطاهای رخ داده به هنگام کدنویسی در اختیار شما قرار می دهد.

5.      کد زیر را جهت فراخوانی متد initializer کلاس والد اضافه نمایید.

super.init(coder: aDecoder)

 

هم اکنون بدنه ی متدinit?(coder:)  بایستی دربردارنده ی پیاده سازی زیر باشد:

required init?(coder aDecoder: NSCoder) {

super.init(coder: aDecoder)

}

به نمایش گذاشتن view اختصاصی

جهت نمایش view دلخواه، می بایست یک view به UI خود اضافه کرده، سپس ارتباطی بین view مورد نظر و کد متناظر آن برقرار نمایید.

جهت به نمایش گذاشتن محتوای view اختصاصی خود در رابط کاربری، مراحل زیر را به ترتیب دنبال نمایید:

1.      ابتدا فایل storyboard را باز نمایید.

2.      داخل storyboard، یک View object از کادر Object library انتخاب کرده، آن را بکشید و در سطح scene جاری جایگذاری نمایید، به طوری که این المان در قالب stackview و زیر آبجکت image view قرار گیرد. 

3.      پس از انتخاب view مورد نظر، کادر Size inspector را با کلیک بر روی آیکون ، در utility area باز نمایید. 

یادآور می شویم که Size inspector با کلیک بر روی دکمه ی پنجم از سمت چپ inspector selector bar باز می شود. در این کادر شما می توانید اندازه و مکان قرار گیری آبجکت مورد نظر را ویرایش نمایید.

4.      از منوی intrinsic size، گزینه ی Placeholder را انتخاب نمایید.  

5.      در زیر منو ی Intrinsic Size، داخل فیلد Height مقدار 44 و داخل فیلد Width مقدار عددی 240 را وارد کنید. اکنون کلید Return را فشار دهید.

در حال حاضر، UI برنامه می بایست ظاهری مشابه زیر داشته باشد.

6.      پس از انتخاب view مورد نظر، کادر  Identity inspector را باز نمایید.

یادآور می شویم که Identity inspector به شما این امکان را می دهد تا آن دسته از property ها و ویژگی های یک آبجکت که با identity آن مرتبط است، نظیر اینکه به کدام کلاس تعلق دارد را ویرایش نمایید. 

7.      داخل این کادر، فیلدی که Class نام دارد را یافته و آن را بر روی RatingControl تنظیم نمایید.

افزودن کنترل Button به View

تا اینجا، اصول اولیه ی یک کلاس فرزند از UIView با پیاده سازی اختصاصی خود (به نام RatingControl) را پایریزی کردید. حال در این بخش تعدادی دکمه به view دلخواه خود اضافه می کنید که کاربر با استفاده از آن ها می تواند به غذای مورد نظر امتیاز بدهد.

کار را با اضافه کردن یک دکمه ی ساده قرمز رنگ آغاز می کنیم که در view به نمایش در می آید.

جهت ایجاد یک دکمه در view اختصاصی خود، مراحل زیر را دنبال کنید:

1.      داخل بدنه ی متد init?(coder:)، دستورات زیر را جهت ایجاد یک دکمه ی قرمز رنگ وارد نمایید:

let button = UIButton(frame: CGRect(x: 0, y: 0, width: 44, height: 44))

button.backgroundColor = UIColor.redColor()

متد redColor()، رنگ کنترل دکمه را بر روی قرمز تنظیم می کند. در صورت تمایل می توانید سایر مقادیر پیش فرض UIColor نظیر blueColor() یا greenColor() را بکار ببرید.

2.      در زیر آخرین خط، کد زیر را وارد کنید:

1.       addSubview(button)

متد addSubview()، دکمه ای که تعریف کردید را به کلاس RatingControl اضافه می کند. 

پیاده سازی متد init?(coder:)  در بدنه بایستی به صورت زیر باشد:

required init?(coder aDecoder: NSCoder) {

super.init(coder: aDecoder)

 

let button = UIButton(frame: CGRect(x: 0, y: 0, width: 44, height: 44))

button.backgroundColor = UIColor.redColor()

addSubview(button)

}

برای اینکه به stack view اعلان کنید چگونه و با چه اندازه ای کنترل دکمه را نمایش دهد، لازم است intrinsic content size آن را مشخص نمایید. برای نیل به این هدف، کافی است پیاده سازی متد intrinsicContentSize را مانند زیر بازنویسی کرده تا پارامترهای تنظیم کننده ی اندازه ی دکمه با اندازه ای که قبلا در Interface Builder (برای کنترل مربوز) مشخص کردید، همخوانی داشته باشد:

override func intrinsicContentSize() -> CGSize {

return CGSize(width: 240, height: 44)

}

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

این دکمه و دکمه های دیگری که به برنامه اضافه می کنید، می بایست با کلیک کاربر، یک action را صدا زده و عملیات خاصی را انجام دهند. آن action تغییر امتیاز یک غذا است. 

به منظور اضافه کردن یک action به کنترل دکمه، مراحل زیر را به ترتیب دنبال نمایید:

1.      داخل فایل RatingControl.swift، قبل از آخرین (})، comment زیر را وارد کنید:

1.       // MARK: Button Action

در زیر comment، تابع زیر را وارد کنید:

func ratingButtonTapped(button: UIButton) {

print("Button pressed ")

}

در زمان حاضر، تابع print() را صرفا جهت کسب اطمینان از متصل بودن متد ratingButtonTapped(_:) به دکمه ی مورد نظر فراخوانی می کنیم. این تابع یک پیغام را در خروجی چاپ می کند. در اینجا منظور از خروجی همان ابزار console در پایین محیط کاری Xcode است که به منظور ثبت گزارش (درباره ی خطاها) و اشکال زدایی کد مورد استفاده قرار می گیرد.  

به زودی پیاده سازی این متد را که در حال حاضر صرفا پیغامی را در console چاپ می کند، با یک عملیات (پیاده سازی) واقعی جایگزین خواهید نمود. 

2.      متد init?(coder:) را پیدا کنید:

required init?(coder aDecoder: NSCoder) {

super.init(coder: aDecoder)

let button = UIButton(frame: CGRect(x: 0, y: 0, width: 44, height: 44))

button.backgroundColor = UIColor.redColor()

addSubview(button)

}

3.      قبل از متد addSubview(button)، این کد را درج نمایید:

2.       button.addTarget(self, action: #selector(RatingControl.ratingButtonTapped(_:)), forControlEvents: .TouchDown)

از قبل با الگوی target-action آشنایی دارید و از آن برای متصل کردن المان های رابط کاربری در storyboard به action method ها در کد استفاده کردید. در بالا همین کار را انجام می دهید، با این تفاوت که اتصال بین کد و المان UI در storyboard را با کدنویسی بر قرار می کنید. بدین صورت که شما متد ratingButtonTapped(_:) را به آبجکت button متصل می کنید و به مجرد اینکه کاربر بر روی دکمه کلیک می کند، رخداد .TouchDown اتفاق افتاده و به دنبال آن متد مذکور اجرا می شود. این رخداد، همان طور که از نامش پیدا است، به برنامه اعلان می کند که کاربر دکمه مورد نظر را فشار داده است.

از آنجایی که action را در سطح کلاس RatingControl تعریف کردید، به واسطه ی کلیدواژه ی self که به کلاس جاری اشاره دارد، همین کلاس را target و دریافت کننده ی پیغام رخداد فشرده شدن دکمه قرار می دهید.

عبارت #selector در خروجی مقدار Selector را برای متد ارائه شده برمی گرداند. Selector یک مقدار opaque است که با استفاده از آن متد خاصی را انتخاب می کنید و در واقع آن متد را به عنوان خروجی برمی گردانید (مقدار opaque مقداری است که جز نوع، هیچ اطلاعات دیگری درباره ی خود بروز نمی دهد).

 API های قدیمی معمولا از selector برای فراخوانی داینامیک متدها در زمان اجرا استفاده می کردند. اگرچه اغلب API های جدید block ها را جایگزین selector کرده اند، با این حال برخی از متدهای قدیمی همچون performSelector(_:) و addTarget(_:action:forControlEvents:) هنوز selector را (برای اشاره به متدی خاص) به عنوان آرگومان می گیرند.

در مثال جاری، عبارت #selector(RatingControl.ratingButtonTapped(_:)) مقدار selector را به عنوان خروجی برای متد #selector(RatingControl.ratingButtonTapped(_:)) برمی گرداند. با این کار به سیستم اجازه می دهید تا به محض فشرده شدن دکمه، متدی (action method) که شما تعریف نموده و به این دکمه متصل کردید را اجرا کند.

از آنجایی که برای ساخت کنترل دکمه از interface builder استفاده ن��ردید، برای تعریف action method نیز نیازی به IBAction ندارید. می توانید action را مانند یک متد معمولی تعریف کنید.   

پس از افزودن دستورات فوق، بدنه ی متد init?(coder:) می بایست به صورت زیر باشد:

required init?(coder aDecoder: NSCoder) {

super.init(coder: aDecoder)

let button = UIButton(frame: CGRect(x: 0, y: 0, width: 44, height: 44))

button.backgroundColor = UIColor.redColor()

button.addTarget(self, action: #selector(RatingControl.ratingButtonTapped(_:)), forControlEvents: .TouchDown)

addSubview(button)

}

تست کنید: برنامه ی خود را اجرا نمایید. به محض کلیک بر روی دکمه ی قرمز رنگ، بایستی پیغام Button pressed را در Console مشاهده نمایید.

اکنون زمان آن فرا رسیده تا اطلاعات لازم جهت امتیازدهی به غذا و نمایش آن امتیاز برای کاربر را در اختیار کلاس RatingControl قرار دهید. در وهله ی اول بایستی مقدار امتیاز –0،1،2،3،4 یا 5- را ذخیره کرده و رصد کنید. سپس دکمه هایی که کاربر با فشردن آن ها امتیاز غذا را مشخص می کند، ایجاد نمایید. می توانید مقدار امتیاز را با نوع int و مجموعه دکمه ها را به وسیله ی آرایه ای از آبجکت های UIButton تعریف نمایید.  

برای این منظور مراحل زیر را دنبال نمایید:

1.      داخل فایل RatingControl.swift، خط تعریف کلاس را پیدا کنید:

class RatingControl: UIView {

2.      در زیر این خط، کد زیر را وارد نمایید:

// MARK: Properties

var rating = 0

var ratingButtons = [UIButton]()

در حال حاضر تنها یک دکمه در view خود دارید، در حالی که برای نمایش میزان محبوبیت غذا و امتیاز آن در کل به 5 دکمه احتیاج دارید. جهت ایجاد این تعداد کنترل دکمه از یک حلقه ی for-in بهره می گیرد. این حلقه در یک دنباله، برای مثال مجموعه ای از اعداد صحیح، پیمایش کرده و یک مجموعه دستور را به دفعات مشخصی تکرار می کند. بجای یک دکمه، این ساختمان کد تعداد کل 5 دکمه را ایجاد می کند.

جهت ایجاد این تعداد کنترل دکمه، مراحل زیر را دنبال نمایید: 

1.      در فایل RatingControl.swift، متد init?(coder:) را پیدا کنید:

required init?(coder aDecoder: NSCoder) {

super.init(coder: aDecoder)

let button = UIButton(frame: CGRect(x: 0, y: 0, width: 44, height: 44))

button.backgroundColor = UIColor.redColor()

button.addTarget(self, action: #selector(RatingControl.ratingButtonTapped(_:)), forControlEvents: .TouchDown)

addSubview(button)

}

2.      حال آن را به صورت زیر ویرایش نمایید:

for _ in 0..<5 {

let button = UIButton(frame: CGRect(x: 0, y: 0, width: 44, height: 44))

button.backgroundColor = UIColor.redColor()

button.addTarget(self, action: #selector(RatingControl.ratingButtonTapped(_:)), forControlEvents: .TouchDown)

addSubview(button)

}

برای سازمان دهی کد و اطمینان از توگذاری صحیح تمامی خط های آن، می توانید کل ساختمان کد را انتخاب کرده و سپس Control-I را فشار دهید. 

لازم به ذکر است که عملگر (..<) خود عدد بزرگ را شامل نمی شود، بنابراین این بازه از 0 شروع شده تا 4 را پیمایش می کند که در کل به 5 بار اجرای دستورات منتهی می شود. در نتیجه ی بجای یک دکمه، با یک حلقه 5 دکمه یکجا ایجاد می کنید. در صورتی که نیازی به آگاهی از گام جاری اجرای (گام تکرار) حلقه نیست، می توانید از (_) استفاده کنید.   

3.      در بالای خط addSubview(button)، این دستور را اضافه کنید:

ratingButtons += [button]

هر کنترل دکمه ای که ایجاد می کنید، جهت ذخیره و رصد مقدارش، آن را به آرایه ی RatingsButtons اضافه می نمایید (تک تک دکمه هایی که با هر بار اجرای حلقه ایجاد می شود را داخل خانه های آرایه مزبور می ریزید).

هم اکنون بدنه ی متدinit?(coder:) می بایست مشابه نمونه ی زیر باشد:

required init?(coder aDecoder: NSCoder) {

super.init(coder: aDecoder)

for _ in 0..<5 {

let button = UIButton(frame: CGRect(x: 0, y: 0, width: 44, height: 44))

button.backgroundColor = UIColor.redColor()

button.addTarget(self, action: #selector(RatingControl.ratingButtonTapped(_:)), forControlEvents: .TouchDown)

ratingButtons += [button]

addSubview(button)

}

}

تست کنید: حال برنامه ی خود را اجرا نمایید. شاید این طور به نظر برسد که در UI برنامه تنها یک دکمه قابل مشاهده است. اما جالب است بدانید که حلقه ی for-in دکمه های ایجاد شده را مانند پشته بر روی هم قرار داده است. به منظور نمایش صحیح کنترل امتیاز دهی، شما باید چیدمان کنترل های دکمه در view را خود تنظیم نمایید.

عملیات لازم جهت تنظیم چیدمان و نمایش صحیح المان ها در UI، داخل بدنه ی متدی به نام layoutSubviews از کلاس UIView تعریف می شود. سیستم این متد را خود در زمان مناسب فراخوانی کرده و از این طریق به کلاس های ارث بری شده از UIView اجازه می دهد تا subview های مورد نظر را به نحو صحیح و با چیدمان دلخواه برنامه نویس در UI نمایش دهند.

برای تنظیم چیدمان کنترل های دکمه، لازم است پیاده سازی متد نام برده را بازنویسی (override) نمایید.

جهت بازنویسی این متد و نمایش دکمه ها در کنار هم، مراحل زیر را به ترتیب طی نمایید:

1.      داخل فایل RatingControl.swift، در زیر متد init?(coder:)، تابع زیر را وارد نمایید:

override func layoutSubviews() {

}

یادآور می شویم که با استفاده از قابلیت code completion محیط کاری Xcode می توانید (اسکلت) این متد را به صورت آماده در کد خود قرار دهید. 

2.      داخل بدنه ی این متد، کد زیر را تایپ کنید:

var buttonFrame = CGRect(x: 0, y: 0, width: 44, height: 44)

// Offset each button's origin by the length of the button plus spacing.

for (index, button) in ratingButtons.enumerate() {

buttonFrame.origin.x = CGFloat(index * (44 + 5))

button.frame = buttonFrame

}

این کد frame دکمه ها را ایجاد می کند، سپس با استفاده از حلقه ی for-in داخل آرایه ی دکمه ها پیمایش کرده و در هر بار اجرا مقادیر (مربوط به) frame هر یک از کنترل های مزبور را تنظیم می نماید.

متد enumerate() در خروجی یک collection برمی گرداند که داخل این collection تک تک المان های آرایه ی ratingButtons همراه با اندیس متناظر آن ها قرار داده شده است. این collection در واقع مجموعه ای از tuple ها (مقادیر گروهی مثال کلید-مقدار) است و در این مثال، هر tuple شامل یک دکمه + اندیس مربوطه ی آن می باشد. حلقه ی for-in که داخل بدنه ی تابع layoutSubviews مشاهده می کنید، مقدار دکمه و اندیس آن را به ترتیب داخل متغیرهای محلی button و index ذخیره می کند (مقدار آن ها را به متغیرهای محلی ذکر شده bind می کند). با استفاده از متغیر index، محل جدید فریم هر دکمه را محاسبه کرده و بعد آن را داخل متغیر button ذخیره می کند. مکان قرارگیری فریم ها برابر اندازه ی استاندارد دکمه با عرض و طول = 44 + padding = 5 (فاصله ی بین دکمه ها) ، ضرب در اندیس (شماره ی مکان قرار گیری) آن دکمه محاسبه و مقداردهی می شود.

در حال حاضر کد موجود در بدنه ی متد layoutSubviews() می بایست مشابه زیر باشد:

override func layoutSubviews() {

var buttonFrame = CGRect(x: 0, y: 0, width: 44, height: 44)

// Offset each button's origin by the length of the button plus spacing.

for (index, button) in ratingButtons.enumerate() {

buttonFrame.origin.x = CGFloat(index * (44 + 5))

button.frame = buttonFrame

}

}

تست کنید: برنامه ی خود را اجرا نمایید. خواهید دید که این بار دکمه ها در کنار هم قرار گرفته اند. یادآور می شویم که کلیک بر روی هر یک از دکمه ها، با توجه به کدی که تا به اینجا برای برنامه ی خود نوشته اید، صرفا سبب فراخوانی متد ratingButtonTapped(_:) و چاپ شدن پیغامی در console می شود.

می توانید console را برای داشتن فضای کاری بیشتر، پنهان نمایید. برای این منظور کافی است بر روی دکمه ی اشاره شده در تصویر زیر کلیک نمایید:

تنظیم میزان فاصله ی دکمه ها از هم و تعداد آن ها (در قالب دو متغیر/property مجزا)

اگر به خاطر داشته باشید، برای تنظیم تعداد کنترل های قابل مشاهده دکمه در UI و میزان فاصله ی بین آن ها، تاکنون در کد خود از عدد 5 استفاده کردید. به طور کلی نگه داشتن مقادیر hardcode شده به صورت پراکنده در متن برنامه روش مطلوب و بهینه ی کدنویسی تلقی نمی شود، چرا که در آن صورت، اگر بخواهید میزان فاصله ی بین دکمه ه�� را ویرایش کنید، می بایست هرجایی در کد که این مقدار به نشانی میزان فاصله ی بین المان ها بکار رفته را پیدا و متعاقبا ویرایش نمایید. حال این امر که مقدار مزبور نشانگر دو چیز کاملا متفاوت در کد شما است (یکی فاصله ی بین دکمه ها و دیگری تعداد آن ها) فقط به پیچیدگی هر چه بیشتر شرایط می افزاید.  

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

جهت تعریف دو متغیر (property) مجزا برای نگهداری فاصله ی بین دکمه ها و تعداد آن ها، مراحل زیر را دنبال نمایید:

1.      داخل فایل RatingControl.swift، بخش // MARK: Properties را پیدا کنید:

// MARK: Properties

var rating = 0

var ratingButtons = [UIButton]()

می توانید با استفاده از functions menu، به سرعت به بخش دلخواه در کد پیمایش کنید (بپرید). این منو با کلیک بر روی اسم فایل، در بالای editor area نمایان می شود.

2.      در زیر property های موجود، کد زیر را وارد نمایید:

let spacing = 5

این ثابت (constant) را جهت تعیین میزان فاصله ی بین دکمه ها در UI، تعریف می کنید.

3.      داخل بدنه ی متد layoutSubviews، مقدار نوشتاری (literal) که برای تعیین میزان فاصله ی بین دکمه ها استفاده می کردید را با ثابت spacing جایگزین نمایید:

buttonFrame.origin.x = CGFloat(index * (44 + spacing))

4.      در زیر ثابت spacing، ثابت دیگری به صورت زیر اضافه نمایید:

let starCount = 5

می توانید این ثابت را جهت تعیین تعداد دکمه هایی (ستاره ها) که کنترل برای کاربر به نمایش می گذارد، بکار ببرید.

5.      اکنون، داخل بدنه ی init?(coder:)، مقدار نوشتاری (literal) که به نشانه ی تعداد دکمه ها در متن برنامه استفاده کردید را با ثابت starCount جایگزین نمایید:

for _ in 0..<starCount {

تست کنید: اپلیکیشن خود را اجرا کنید. رفتار و ظاهر برنامه نباید نسبت به قبل تغییری کرده باشد.

تعریف یک ثابت جهت تعیین اندازه ی کنترل دکمه

اگر بخاطر داشته باشید، مقدار 44 را به نشانه ی اندازه ی کنترل دکمه، در کد خود بکار بردید. اما همان طور که قبلا گفته شد، مقادیر hardcode شده به صورت پراکنده در کد مطلوب نیست و بهتر است این روش کدنویسی را از متن برنامه ی خود حذف کنید. این بار دکمه ها را طوری تنظیم می کنید که خود را با اندازه ی view میزبان تطبیق دهند (container view ای که در ابتدای مبحث به storyboard خود اضافه کردید). این کار را با بازیابی مقدار طول (height) view میزبان و ذخیره ی آن داخل یک ثابت محلی انجام می دهید، سپس به راحتی و تنها یکبار از داخل هر متد به آن دست پیدا می کنید.    

جهت تعریف یک ثابت، برای ذخیره و نگهداری اندازه ی دکمه های کنترل امتیازدهی، مراحل زیر طی نمایید:

1.      داخل بدنه ی متد layoutSubviews()، این کد را قبل از اولین خط پیاده سازی اضافه نمایید:

// Set the button's width and height to a square the size of the frame's height.

let buttonSize = Int(frame.size.height)

با افزودن این کد layout را به طور قابل توجهی انعطاف پذیرتر می سازید.

2.      حال ثابت buttonSize را جایگزین مقدار 44 در بقیه ی کد نمایید:

var buttonFrame = CGRect(x: 0, y: 0, width: buttonSize, height: buttonSize)

// Offset each button's origin by the length of the button plus spacing.

for (index, button) in ratingButtons.enumerate() {

buttonFrame.origin.x = CGFloat(index * (buttonSize + 5))

button.frame = buttonFrame

}

برای اینکه stack view کنترل امتیاز دهی را به صورت دلخواه نمایش دهد، لازم است intrinsic content size (اندازه ی درونی) کنترل مورد نظر را بروز رسانی نمایید. این بار محاسبه ی اندازه ی هر یک از دکمه ها (ستاره ها) و فاصله ی بین آن ها را به متد intrinsicContentSize() واگذار می کنید.

برای این منظور کافی است کد زیر را بکار ببرید:

let buttonSize = Int(frame.size.height)

let width = (buttonSize * starCount) + (spacing * (starCount - 1))

return CGSize(width: width, height: buttonSize)

در متد init?(coder:)، اولین خط کد داخل ساختمان حلقه ی for-in را به صورت زیر ویرایش کنید:

let button = UIButton()

از آنجایی که پراپرتی frame دکمه ها را داخل متد layoutSubviews() تنظیم می کنید، دیگر در زمان ایجاد دکمه ها نیازی به مقدار دهی آن ها نیست.

کد موجود در بدنه ی متد layoutSubviews() اکنون می بایست مشابه نمونه ی زیر باشد:

override func layoutSubviews() {

// Set the button's width and height to a square the size of the frame's height.

let buttonSize = Int(frame.size.height)

var buttonFrame = CGRect(x: 0, y: 0, width: buttonSize, height: buttonSize)

// Offset each button's origin by the length of the button plus some spacing.

for (index, button) in ratingButtons.enumerate() {

buttonFrame.origin.x = CGFloat(index * (buttonSize + 5))

button.frame = buttonFrame

}

}

کد موجود در بدنه ی متد intrinsicContentSize می بایست مشابه نمونه ی زیر باشد:

override func intrinsicContentSize() -> CGSize {

let buttonSize = Int(frame.size.height)

let width = (buttonSize * starCount) + (spacing * (starCount - 1))

return CGSize(width: width, height: buttonSize)

}

بدنه ی متد init?(coder:) نیز بایستی مانند زیر باشد:

required init?(coder aDecoder: NSCoder) {

super.init(coder: aDecoder)

for _ in 0..<5 {

let button = UIButton()

button.backgroundColor = UIColor.redColor()

button.addTarget(self, action: #selector(RatingControl.ratingButtonTapped(_:)), forControlEvents: .TouchDown)

ratingButtons += [button]

addSubview(button)

}

}

تست کنید: برنامه را اجرا کنید. رفتار و ظاهر برنامه نسبت به قبل تغییر خاصی نکرده است. دکمه ها باید در کنار هم قرار گرفته باشند و کلیک بر روی هر کدام از دکمه ها هنوز بایستی سبب فراخوانی متد ratingButtonTapped(_:) شده و پیغامی را  در console ثبت کند. 

جایگزین کردن عکس ستاره بجای مربع های قرمز رنگ

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

 

می توانید تصاویر فوق را در پوشه ی Images/ از فایل پروژه ی دانلود شده انتخاب کنید یا در صورت تمایل تصاویر دلخواه خود را بکار ببرید. (کافی است مطمئن شوید اسم عکس های مورد استفاده ی شما با اسم عکس ها در کد کاملا همخوانی داشته باشد).  

به منظور افزودن تصویر به پروژه ی خود، مراحل زیر را طی نمایید:

1.      داخل project navigator، با کلیک بر روی Assets.xcassets، ابزار asset catalog را باز کنید.  

یادآور می شویم که asset catalog مکانی است که در آن محتوای برنامه ی خود نظیر عکس، متن و غیره را مدیریت می کنید.

2.      در گوشه ی سمت چپ، بر روی دکمه ی + کلیک کرده و پوشه ی New Folder را از منوی pop-up انتخاب نمایید.

3.      بر روی اسم پوشه دابل کلیک کرده و آن را به Rating Images تغییر دهید.

4.      پس از انتخاب پوشه ی مذکور، در گوشه ی سمت چپ، بر روی دکمه ی (+) کلیک کرده و سپس گزینه ی New Image Set را از منوی pop-up انتخاب نمایید.

هر Image set به منزله ی یک image asset واحد است اما می تواند نسخه های مختلفی از یک عکس را در وضوح تصویر متفاوت داشته باشد.

5.      بر روی اسم image set دابل کلیک کرده و سپس آن را به emptyStar تغییر دهید.

6.      حال عکس ستاره ی خالی را از حافظه ی کامپیوتر انتخاب نمایید.

7.      عکس را کشیده و آن را در فضای خالی 2x داخل image set جاری جایگذاری نمایید. 

2x وضوح تصویر نمایشگر شبیه ساز iPhone 6 می باشد که برنامه ی خود را در محیط آن تست می کنید. عکس مورد نظر قاعدتا باید در این وضوح با بهترین کیفیت نمایش داده شود.

8.      در پایین محیط، گوشه ی سمت چپ، بر روی دکمه ی (+) کلیک کنید و سپس گزینه ی New Image Set را از منوی pop-up انتخاب نمایید.

9.      بر روی اسم image set دو بار کلیک کرده و آن را به filledStar تغییر دهید.

10.   اکنون عکس ستاره ی پر شده را از حافظه ی کامپیوتر خود انتخاب نمایید.

11.   عکس مورد نظر را کشیده و آن را در فضای خالی 2x، داخل image set جاری جایگذاری نمایید.

Asset catalog شما هم اکنون می بایست مشابه زیر باشد:

در گام بعدی کدی می نویسید که عکس مربوطه را در زمان مناسب برای دکمه تنظیم کرده و نمایش می دهد.

جهت تنظیم عکس برای نمایش، مراحل زیر را به ترتیب دنبال نمایید:

1.      فایل RatingControl.swift را باز کنید.

2.      داخل بدنه ی متد init?(coder:)، دو خط زیر را به قبل از ساختمان حلقه ی for-in اضافه نمایید:

let filledStarImage = UIImage(named: "filledStar")

let emptyStarImage = UIImage(named: "emptyStar")

3.      داخل قطعه کد for-in، پس از آن خطی از کد که دکمه در آن مقداردهی اولیه (initialize) می شود، دستورات زیر را درج کنید:

button.setImage(emptyStarImage, forState: .Normal)

button.setImage(filledStarImage, forState: .Selected)

button.setImage(filledStarImage, forState: [.Highlighted, .Selected])

شما برای هر یک از دو حالت دکمه یک عکس مجزا تخصیص می دهید تا بتوانید به راحتی تشخیص دهید چه زمانی دکمه انتخاب شده و چه زمانی کاربر هنوز بر روی دکمه کلیک نکرده است. عکس ستاره ی خالی زمانی نمایش داده می شود که دکمه انتخاب نشده باشد (وضعیت.Normal ). عکس ستاره ی پر شده زمانی نمایش داده می شود که دکمه انتخاب شده (.Selected ) و همچنین زمانی که دکمه همزمان انتخاب و هایلایت شده باشد (.Selected و .Highlighted= وضعیتی که کاربر در حال ضربه زدن بر روی دکمه باشد.)

4.      آن خطی از برنامه که رنگ پس زمینه ی دکمه را بر روی قرمز تنظیم می کند، حذف نمایید:

button.backgroundColor = UIColor.redColor()

از آنجایی که دکمه های شما اکنون عکس های خود را دارند، زمان آن رسیده تا رنگ پس زمینه ی دکمه را حذف نمایید.

5.      کد زیر را اضافه نمایید:

button.adjustsImageWhenHighlighted = false

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

در حال حاضر کد init?(coder:) شما بایستی به صورت زیر باشد:

required init?(coder aDecoder: NSCoder) {

super.init(coder: aDecoder)

let emptyStarImage = UIImage(named: "emptyStar")

let filledStarImage = UIImage(named: "filledStar")

for _ in 0..<5 {

let button = UIButton()

button.setImage(emptyStarImage, forState: .Normal)

button.setImage(filledStarImage,