Custom Snack Bar | سفارشی سازی اسنک بار

سلام دوستان امیدوارم با این همه اتفاقات حال دل همتون خوب و غمتون کم باشه !21/11/1398نمیخوام زیاد وقتتون رو با مقدمه و این حرفا بگیرم چون هم وقت طلاست هم اینکه شما نمیخونید :)اسنک بار چیست ؟ | What is SnackBar اسنک بار میشه گفت همون Toast با امکانات بیشتر و اجرای روان‌تر که از اندروید ۵ به بعد معرفی شد و توی طراحی های متریال فوق العاده پرکاربردهاسنک‌بار در پایین صفحه نمایش (پیشفرض) داده می‌شه و شامل یک متن و یک دکمه عملیات (اختیاری) هست. کاربر می‌تونه روی دکمه عملیات کلیک کنه یا اون رو به طرفین بکشه تا از روی صفحه محو بشه. اگه کاربر هیچکدوم از این کارها را نکنه، بعد از مدتی اسنک‌بار خود به خود محو می‌شه.اسنک بار ساده !قدم اول : فایل build.gradle پروژتون رو باز کنید و کد زیر رو بهش اضافه کنید .dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:23.0.1' compile 'com.android.support:design:23.0.1' }قدم دوم : کد زیر Snackbar ای میسازه که فقط یک متن رو نمایش میده .Snackbar snackbar = Snackbar.make(rootView, &quotThis is our Snackbar Sample !!&quot, Snackbar.LENGTH_LONG); snackbar.show();تابع make سه پارامتر به عنوان ورودی میگیره : پارامتر اول : view مادر (لایوت نمایش دهنده اسنک بار) که قراره توی اون Snackbar رو نمایش بدیم پارامتر دوم : متنی هست که میخوایم نمایش بدیمسومین پارامتر : مدت زمانی هست که قراره snackbar به کاربرانمون نشون داده بشه : LENGTH_LONG : مدت زمان زیاد LENGTH_SHORT : مدت زمان کوتاه LENGTH_INDEFINITE : تا زمانی که به وسیله کشیدن از صفحه خارج نشه ، نشون داده خواهد شد .نکته : در مستندات گوگل توصیه شده که برای view اصلی (مادر) که قراره snackbar در اون نمایش داده بشه و به عنوان پارامتر اول به تابع make ارسال بشه از CoordinatorLayoutاستفاده کنید ، تا تمام قابلیت‌های پیش فرض snackbar مثل کشیدن برای از بین بردن ( swipe dissmiss ) و خارج شدن اتوماتیک از کنار صفحه قابل استفاده باشهAction Button : خب حالا فرض کنید به وسیله snackbarمیخوایم از کاربرامون یک تاییدیه بگیریم.Snackbar snackbar = Snackbar.make(coordinatorLayout, &quotMessage is deleted&quot, Snackbar.LENGTH_LONG).setAction(&quotUNDO&quot, new View.Listener() { @Override public void (View view) { Snackbar snackbar1 = Snackbar.make(coordinatorLayout, &quotMessage is restored!&quot, Snackbar.LENGTH_SHORT); snackbar1.show(); } }); snackbar.show();توی بالا با استفاده از تابع setAction یک عملیات رو برای snackbar مون تعریف میکنیم تابع setAction دوتا ورودی میگیره ، اولی اسمی هست که میخوایم برای عملیاتمون نمایش بدیم و دومی یک Listener .Simple Snack Bar سفارشی سازی خب وقتی مراحل بالا رو برید متوجه میشید که اسنک بارتون خیلی سادست و اصلا شبیه اون چیزی که توی توییتر و یا جیمیل ( یا جاهای دیگه ) نیست Custom Snack Bar ( Twitter )مثلا رنگ دلخواهتون نیست و یا گوشه هاش خمیده نیست ( corner radius ) یا کاملا چسبیده به اطراف...برای این کار یه کلاس میسازم به اسم SnackBarHelper :public class SnackBarHelper { public static void configSnackbar(Context context, Snackbar snack) { } }برای این کلاس یک کانستراکتور میسازم که بتونم Context و SnackBar رو بگیرم و روشون تغییرات رو اعمال کنم قدم اول برای اضافه کردن Elevation به اسنک بارم میتونم توی کانستراکتورم این خط کد رو اعمال کنم :public class SnackBarHelper { public static void configSnackbar(Context context, Snackbar snack) { ViewCompat.setElevation(snack.getView(), 6f); } }که دوتا پارامتر میگیره : اول : ویو اسنک بار مادوم : مقدار Elevationدر ادامه میخوام چند تابع ( به نظرم من پرکاربرد ترینشون ) رو براتون بگم که تو این کلاس شما میتونید بعدا هرچی خواستین اضافه کنید :تابع اول ( راست چین کردن | Set To Rtl ) این تابع برای فارسی زبان ها بیشتر کاربرد داره وقتی اسنک بار میسازید مسیج داخلش چپ چینه و برای فیکس کردن این موضوع از تابع زیر استفاده میکنیم:private static void setToRtl(Snackbar snackbar) { ViewCompat.setLayoutDirection(snackbar.getView(), ViewCompat.LAYOUT_DIRECTION_RTL); }تابع دوم ( فاصله دادن از اطراف | Set Margin ) وقتی اسنک بار میسازید کلا چسبیده به اطراف و هیچ فاصله ای ( margin ) نداره برای فاصله دادن از اطراف از تابع زیر استفاده میکنیم :private static void addMargins(Snackbar snack) { ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) snack.getView().getLayoutParams(); params.setMargins(12, 12, 12, Function.snackMargin); // میتونید مقدار مارجین ها رو به مقدار دلخواه تغییر بدید snack.getView().setLayoutParams(params); } اون پارامتری که من نوشتم Function.snackMargin یه متغییریه که با تابعی که نوشتم و در اخر توضیح میدم متوجه میشه که کیبورد باز شده یا نه چون اسنک پشت کیبورد میره و معلوم نمیشه و ارتفاع کیبورد رو میگیره و به عنوان مارجین پایین بهش ست میشه .تابع سوم ( Set Drawable ) توی این تابع شما میتونید هر drawable بهش بدید تا کاستومایز شما بشه این Drawable منه : <?xml version=&quot1.0&quot encoding=&quotutf-8&quot?> <shape xmlns:android=&quothttp://schemas.android.com/apk/res/android&quot android:shape=&quotrectangle&quot> <solid android:color=&quot#323232&quot /> <corners android:radius=&quot4dp&quot /> </shape>و این هم تابع : private static void setDrawable (Context context, Snackbar snackbar) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { snackbar.getView().setBackground(context.getDrawable(R.drawable.contianer_snackbar)); } }تابع چهارم ( تغییر فونت | Set Type Face) معمولا ما از فونت های خاص خودمون توی اپلیکیشن ها استفاده میکنیم خب اسنک بارمون هم که نمیشه فونت پیشفرض داشته باشه , برای اعمال فونت خاص خودمون از تابع زیر استفاده کنید : private static void setTypeFace(Context context, Snackbar snackbar) { TextView tv = (snackbar.getView()).findViewById(com.google.android.material.R.id.snackbar_text); TextView snackbarActionTextView = snackbar.getView().findViewById(com.google.android.material.R.id.snackbar_action ); Typeface font = Typeface.createFromAsset(context.getAssets(),&quotfonts/IranSansRegular.ttf&quot); Typeface bold =Typeface.createFromAsset(context.getAssets(), &quotfonts/IranSansMedium.ttf&quot); tv.setTypeface(font); snackbarActionTextView.setTypeface(bold); }تابع پنجم ( تغییر رنگ دکمه اسنک بار )وقتی برای اسنک بار دکمه میزارید بهتره که رنگشو عوض کنید تا کاربر متوجه بشه این فقط تکست نیست و یک عملی انجام میده :private static void changeActionTextColor(Snackbar snackbar , Context context) { snackbar.setActionTextColor(context.getResources().getColor(R.color.colorWhite)) }کد نهایی : و همه تابع ها رو توی کانستراکتور صدا میزنیم :public class SnackBarHelper { public static void configSnackbar(Context context, Snackbar snack) { addMargins(snack); setRoundBordersBg(context, snack); setTypeFace(context, snack); setToRtl(snack); ViewCompat.setElevation(snack.getView(), 6f); changeActionTextColor(snack , context); } private static void setToRtl(Snackbar snackbar) { ViewCompat.setLayoutDirection(snackbar.getView(), ViewCompat.LAYOUT_DIRECTION_RTL); } private static void changeActionTextColor(Snackbar snackbar , Context context) { snackbar.setActionTextColor(context.getResources().getColor(R.color.colorWhite)) } private static void addMargins(Snackbar snack) { ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) snack.getView().getLayoutParams(); params.setMargins(12, 12, 12, Funcations.SnackMargin); snack.getView().setLayoutParams(params); } private static void setRoundBordersBg(Context context, Snackbar snackbar) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { snackbar.getView().setBackground(context.getDrawable(R.drawable.contianer_snackbar)); } } private static void setTypeFace(Context context, Snackbar snackbar) { TextView tv =(snackbar.getView()).findViewById(com.google.android.material.R.id.snackbar_text); TextView snackbarActionTextView = snackbar.getView().findViewById(com.google.android.material.R.id.snackbar_action ); Typeface font = Typeface.createFromAsset(context.getAssets(), &quotfonts/IranSansRegular.ttf&quot); Typeface bold = Typeface.createFromAsset(context.getAssets(), &quotfonts/IranSansMedium.ttf&quot); tv.setTypeface(font); snackbarActionTextView.setTypeface(bold); } }My Final Snack Barتابع Keyboard Listenerاز این تابع که یکمی بالاتر ازش حرف زدم برای باز بودن یا نبودن کیبورد استفاده میکنم که بتونم مقدار ارتفاعشو به عنوان مارجین پایین ست کنم به اسنک بارم : public static boolean isKeyboardHidden = false; public static int SnackMargin = 12; public static void keyBoardListener(final Activity activity) { final View activityRootView = activity.findViewById(android.R.id.content); activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { Rect rect = new Rect(); activityRootView.getWindowVisibleDisplayFrame(rect); int heightRoot = activityRootView.getRootView().getHeight(); int heightDiff = heightRoot - rect.bottom; if (heightDiff > dpToPx(activity, 200)) { if (!isKeyboardHidden) { isKeyboardHidden = true; SnackMargin = heightDiff + 15; } } else if (heightDiff < dpToPx(activity, 200)) { if (isKeyboardHidden) { isKeyboardHidden = false; SnackMargin = 12; } } } }); }این تابع رو تو onCreate هر اکیتیوتی که قرار توش اسنک بار رو استفاده کنم صدا میزنم و بعد از متغییر snackMargin استفاده میکنم تا مارجین پایین رو ست کنم و اسنک بیاد بالای کیبورد و در نهایت برای اعمال تغییرات روی اسنک بارم از کد زیر استفاده میکنم : Snackbar snack = Snackbar.make( activity.findViewById(android.R.id.content), message, Snackbar.LENGTH_LONG ); SnackBarHelper.configSnackbar(activity, snack); snack.show();امیداورم که تونسته باشم دانش کوچیکم رو به شما دوستان انتقال داده باشم 3>اگه جایی اشتباهی کردم یا گنگ بوده هم معذرت میخوام و هم من در خدمت شما هستم !