캐러셀 구현
BuzzAd Android용 SDK v3.5.x부터 추가된 캐러셀(Carousel)은 여러 개의 광고를 가로로 스크롤 하여 사용자에게 노출할 수 있는 UI입니다. BuzzAd Android용 SDK를 사용하여 Native 지면에 캐러셀을 생성하고 필수 기능을 구현해 캐러셀을 구현할 수 있습니다. 또한 선택에 따라 구현할 수 있는 부가 기능들을 통해 사용자 경험을 최적화할 수도 있습니다.

캐러셀 구현하기
BuzzAd Android용 SDK에서는 아이템 뷰를 화면에 가로 레이아웃으로 표시하는 RecyclerView와 이를 처리하는 어댑터를 사용하여 네이티브 지면에 캐러셀을 구현할 수 있습니다.
RecyclerView 생성하기
RecyclerView를 생성하려면 다음의 절차를 따르세요.
-
캐러셀을 넣고 싶은 영역에
RecyclerView를 추가한 액티비티 레이아웃 파일(activity_native_carousel.xml)을 구현하세요..... <androidx.recyclerview.widget.RecyclerView android:id="@+id/carousel" android:layout_width="match_parent" android:layout_height="wrap_content" /> .... -
뷰 레이아웃 파일(
view_item_carousel.xml)에RecyclerView의 각 아이템에 대한 레이아웃을 작성하세요.<?xml version="1.0" encoding="utf-8"?> <com.buzzvil.buzzad.benefit.presentation.nativead.NativeAdView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content"> .... </com.buzzvil.buzzad.benefit.presentation.nativead.NativeAdView> -
RecyclerView의 각 아이템을 담당할CarouselItem클래스를 선언하세요.다음은 기반 클래스인
CarouselItem을 선언하고, 이를 확장해서 광고 객체를 들고 있는NativeAdItem클래스를 선언하는 예시입니다.class CarouselItem { // NativeAd를 가지고 있는 아이템 static class NativeAdItem extends CarouselItem { public final NativeAd nativeAd; NativeAdItem(final NativeAd nativeAd) { this.nativeAd = nativeAd; } } } -
RecyclerView에 들어갈 아이템이 다음과 같이 생성되는지 확인하세요.val newItem = new CarouselItem.NativeAdItem(nativeAd);
RecyclerView 어댑터 구현하기
RecyclerView 어댑터를 구현하려면 캐러셀을 처리하기 위한 어댑터와 어댑터 내의 CarouselDiff 및 ViewHolder를 구현해야 합니다. 다음의 절차를 따르세요.
-
캐러셀을 처리하기 위한 어댑터(
CarouselAdapter)를 구현하세요.ListAdapter나RecyclerView.Adapter를 확장하여 어댑터를 구현할 수 있습니다.다음은
ListAdapter를 확장하여 구현하는 예시입니다.class CarouselAdapter extends ListAdapter<CarouselItem, CarouselAdapter.ViewHolder> { public CarouselAdapter() { super(new CarouselDiff()); } @Override public CarouselAdapter.ViewHolder onCreateViewHolder( ViewGroup parent, int viewType ) { return new ViewHolder(ViewItemCarouselBinding.inflate(LayoutInflater.from(parent.getContext()))); } @Override public void onBindViewHolder(final CarouselAdapter.ViewHolder holder, final int position) { final CarouselItem item = getItem(position); if (item instanceof CarouselItem.NativeAdItem) { holder.bind(((CarouselItem.NativeAdItem) item).nativeAd); } } @Override public void onViewRecycled(final ViewHolder holder) { super.onViewRecycled(holder); // unbind를 반드시 호출하여 NativeAd나 FeedPromotion을 재사용할 때 문제가 발생하지 않게 합니다. holder.unbind(); } private static class CarouselDiff extends DiffUtil.ItemCallback<CarouselItem> { // TODO } protected static class ViewHolder extends RecyclerView.ViewHolder { // TODO } } -
어댑터에 대한 업데이트를 콜백하는 하위 클래스
CarouselDiff를 구현하세요.private static class CarouselDiff extends DiffUtil.ItemCallback<CarouselItem> { @Override public boolean areItemsTheSame(final CarouselItem oldItem, final CarouselItem newItem) { if (oldItem instanceof CarouselItem.NativeAdItem && newItem instanceof CarouselItem.NativeAdItem && ((CarouselItem.NativeAdItem) oldItem).nativeAd == ((CarouselItem.NativeAdItem) newItem).nativeAd) { return true; } else if (oldItem instanceof CarouselItem.CarouselToFeedSlideItem && newItem instanceof CarouselItem.CarouselToFeedSlideItem) { return true; } return false; } @Override public boolean areContentsTheSame(final CarouselItem oldItem, final CarouselItem newItem) { if (oldItem instanceof CarouselItem.NativeAdItem && newItem instanceof CarouselItem.NativeAdItem && ((CarouselItem.NativeAdItem) oldItem).nativeAd.getId() == ((CarouselItem.NativeAdItem) newItem).nativeAd.getId()) { return true; } else if (oldItem instanceof CarouselItem.CarouselToFeedSlideItem && newItem instanceof CarouselItem.CarouselToFeedSlideItem) { return true; } return false; } } -
레이아웃에 정의한 각 뷰에
NativeAd의 요소가 정상적으로 설정될 수 있도록 하위 클래스인ViewHolder를 구현하세요.
-
ViewHolder는NativeAdViewBinder를 이용합니다.protected static class ViewHolder extends RecyclerView.ViewHolder { // 레이아웃과 NativeAd를 연결해주는 ViewBinder private final NativeAdViewBinder nativeAdViewBinder; public ViewHolder(final ViewItemCarouselBinding binding) { super(binding.getRoot()); nativeAdViewBinder = new NativeAdViewBinder.Builder( binding.getRoot(), binding.adMediaView ) .titleTextView(binding.adTitleText) .descriptionTextView(binding.adDescriptionText) .iconImageView(binding.adIconImage) .ctaView(binding.adCtaView) .build(); } /** * 레이아웃과 NativeAd를 연결합니다. * * @param nativeAd: 레이아웃에 연결할 NativeAd 객체 */ void bind(final NativeAd nativeAd) { nativeAdViewBinder.bind(nativeAd); } /** * 레이아웃과 NativeAd 간의 연결을 해제합니다. */ void unbind() { this.nativeAdViewBinder.unbind(); } }
액티비티 또는 프래그먼트에 결합하기
생성을 완료한 RecyclerView와 어댑터를 액티비티 혹은 프래그먼트에 bind하여 사용할 수 있습니다.
다음은 RecyclerView와 어댑터를 액티비티(NativeCarouselActivity)에 bind하는 예시입니다.
/**
* BuzzAd SDK를 사용하여 Carousel UI를 구현하는 방법에 대한 예제 코드
*/
public class NativeCarouselActivity extends AppCompatActivity {
private ActivityNativeCarouselBinding binding;
private CarouselAdapter adapter;
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityNativeCarouselBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
adapter = new CarouselAdapter();
}
}
액티비티에 RecyclerView와 어댑터를 결합하려면 다음의 절차를 따르세요.
- 캐러셀 초기화 함수를 호출한 후 RecyclerView에 CarouselAdapter를 할당하세요.
-
PagerSnapHelper: 캐러셀의 스크롤이 중간에 멈추지 않고 각 광고 아이템이 온전히 노출되는 방향으로 자연스럽게 동작하게 됩니다.PagerSnapHelper에 대한 자세한 내용은 Android 공식 문서를 참고하세요.public class NativeCarouselActivity extends AppCompatActivity { .... @Override public void onCreate(final Bundle savedInstanceState) { .... initCarousel(); } private void initCarousel() { binding.carousel.setAdapter(adapter); // ViewPager와 비슷하게, 스크롤이 중간에서 멈추면 한쪽 아이템을 선택하여 다 보일 때까지 스크롤 new PagerSnapHelper().attachToRecyclerView(binding.carousel); } }
-
RecyclerView에 LayoutManager(
LinearLayoutManager)를 할당한 후 광고 아이템 배치 방향 파라미터를HORIZONTAL로 설정하세요. 그런 다음,checkLayoutParams에서 각 아이템이 화면 폭 전체를 차지하도록 설정하세요.public class NativeCarouselActivity extends AppCompatActivity { .... // LinearLayoutManager를 사용하고 HORIZONTAL로 설정하여 수평으로 일렬로 정렬된 레이아웃을 사용합니다. private final LinearLayoutManager layoutManager = new LinearLayoutManager( this, HORIZONTAL, false ) { // Carousel 아이템의 폭이 화면을 채우도록 변경합니다. @Override public boolean checkLayoutParams(final RecyclerView.LayoutParams lp) { lp.width = getWidth(); return true; } }; .... private void initCarousel() { .... binding.carousel.setLayoutManager(layoutManager); .... } } -
광고를 요청하는 코드를 호출하세요.
-
onError(): 광고 로딩 오류가 발생할 때 호출됩니다. -
onEmpty(): 노출할 수 있는 광고가 없을 때 호출됩니다. -
onAdsLoaded(): 요청할 수 있는 광고가 있을 때 호출됩니다.public class NativeCarouselActivity extends AppCompatActivity { .... // Carousel 지면에서 사용할 Unit ID private final String unitId = App.UNIT_ID_NATIVE_AD; .... private final NativeAdLoader.OnAdsLoadedListener adsLoadedListener = new NativeAdLoader.OnAdsLoadedListener() { @Override public void onLoadError(final AdError error) { onError(); } @Override public void onAdsLoaded(final Collection<NativeAd> nativeAds) { if (nativeAds.isEmpty()) { onEmpty(); } else { NativeCarouselActivity.this.onAdsLoaded(nativeAds); } } }; ... @Override public void onCreate(final Bundle savedInstanceState) { .... loadAds(); } .... private void loadAds() { new NativeAdLoader(unitId).loadAds( adsLoadedListener, new NativeAdLoaderParams.Builder() .count(5) .build() ); } }
-
광고 요청 결과에 따른 동작을 구현하세요.
public class NativeCarouselActivity extends AppCompatActivity { .... private void onError() { // 오류가 발생하면 지면을 표시하지 않습니다. binding.placement.setVisibility(View.GONE); Log.d(TAG, "An error occurred while loading ads"); } private void onEmpty() { // 보여줄 광고가 없으면 지면을 표시하지 않습니다. binding.placement.setVisibility(View.GONE); Log.d(TAG, "The ad list is empty"); } private void onAdsLoaded(final Collection<NativeAd> nativeAds) { binding.placement.setVisibility(View.VISIBLE); final List<CarouselItem> items = buildCarouselItems(nativeAds); adapter.submitList(items); Log.d(TAG, "" + nativeAds.size() + " Ads are loaded"); } } -
NativeAd객체를CarouselItem으로 변경하는 코드를 작성하세요.public class NativeCarouselActivity extends AppCompatActivity { .... /** * NativeAd 배열을 Carousel에 채워넣을 CarouselItem으로 변환하는 함수 * * @param nativeAds: Carousel에 표시할 광고 객체 배열 */ private List<CarouselItem> buildCarouselItems(final Collection<NativeAd> nativeAds) { List<CarouselItem> items = new ArrayList<>(); for (final NativeAd nativeAd : nativeAds) { items.add(new CarouselItem.NativeAdItem(nativeAd)); } return items; } }
캐러셀의 필수 기능 구현하기
BuzzAd Android용 SDK는 다양한 광고 및 사용자가 취향에 맞게 광고를 필터링할 수 있는 피드 지면 진입 경로인 슬라이드 페이지와 엔트리 포인트를 제공합니다.
피드 진입 슬라이드
피드로 진입할 수 있는 슬라이드(Carousel To Feed Slide)를 캐러셀에 구현할 수 있습니다. 캐러셀 내에서 원하는 순서에 피드 진입 슬라이드를 추가할 수 있으며 추가 갯수 제한도 없어 광고 사이사이에 앱 수익화 효과가 가장 높은 피드로의 진입점을 자유롭게 추가할 수 있습니다. 이를 위해 BuzzAd Android용 SDK는 아래 표에 나열된 클래스를 제공합니다.

| 코드 | 설명 |
|---|---|
FeedPromotion | 피드 진입 슬라이드에 표시할 리소스(이미지, 문구)를 가지고 있는 객체입니다. |
FeedPromotionFactory | FeedPromotion 객체를 생성합니다.
|
FeedPromotionViewBinder | NativeAdView에 FeedPromotion을 보여줄 수 있도록 연결합니다.
|
피드 진입 슬라이드를 구현하려면 다음의 절차를 따르세요.
-
CarouselItem에서 피드 진입 슬라이드를 보여주기 위한 클래스의 선언을 추가하세요.다음은 기존의
CarouselItem구현에서CarouselToFeedSlideItem클래스의 선언을 추가하는 예시입니다.class CarouselItem { // NativeAd를 가지고 있는 아이템 static class NativeAdItem extends CarouselItem { public final NativeAd nativeAd; NativeAdItem(final NativeAd nativeAd) { this.nativeAd = nativeAd; } } // Carousel To Feed Slide를 가지고 있는 아이템 static class CarouselToFeedSlideItem extends CarouselItem { public final FeedPromotion feedPromotion; CarouselToFeedSlideItem(final FeedPromotion feedPromotion) { this.feedPromotion = feedPromotion; } } } -
CarouselToFeedSlideItem에 맞는 동작을 구현하기 위해 어댑터(CarouselAdapter)를 구현하세요.i.
onBindeViewHolder에서CarouselToFeedSlideItem일 때 호출할 bind 함수를 연결하세요.class CarouselAdapter extends ListAdapter<CarouselItem, CarouselAdapter.ViewHolder> { .... @Override public void onBindViewHolder(final CarouselAdapter.ViewHolder holder, final int position) { final CarouselItem item = getItem(position); if (item instanceof CarouselItem.NativeAdItem) { holder.bind(((CarouselItem.NativeAdItem) item).nativeAd); } else if (item instanceof CarouselItem.CarouselToFeedSlideItem) { holder.bind(((CarouselItem.CarouselToFeedSlideItem) item).feedPromotion); } } .... }ii. ViewHolder를 구현하세요. 구현 시
FeedPromotion을 받아서FeedPromotionViewBinder를 이용해NativeAdView에 각 요소가 잘 연결될 수 있도록 해야 합니다.
또한 기존에 작성한 코드에서NativeAdViewBinder와 비슷하게 객체를 생성한 후 bind 함수를 만든 다음unbind()를 호출하도록 코드를 추가하세요.class CarouselAdapter extends ListAdapter<CarouselItem, CarouselAdapter.ViewHolder> { .... protected static class ViewHolder extends RecyclerView.ViewHolder { // 레이아웃과 NativeAd를 연결해주는 ViewBinder private final NativeAdViewBinder nativeAdViewBinder; // 레이아웃과 FeedPromotion을 연결해주는 ViewBinder private final FeedPromotionViewBinder carouselToFeedSlideViewBinder; public ViewHolder(final ViewItemCarouselBinding binding) { super(binding.getRoot()); nativeAdViewBinder = new NativeAdViewBinder.Builder( binding.getRoot(), binding.adMediaView ) .titleTextView(binding.adTitleText) .descriptionTextView(binding.adDescriptionText) .iconImageView(binding.adIconImage) .ctaView(binding.adCtaView) .build(); carouselToFeedSlideViewBinder = new FeedPromotionViewBinder.Builder( binding.getRoot(), binding.adMediaView ) .titleTextView(binding.adTitleText) .descriptionTextView(binding.adDescriptionText) .iconImageView(binding.adIconImage) .ctaView(binding.adCtaView) .build(); } .... /** * 레이아웃과 FeedPromotion을 연결하여 Carousel To Feed Slide를 만듭니다. * * @param feedPromotion: 레이아웃에 연결할 FeedPromotion 객체 */ void bind(final FeedPromotion feedPromotion) { carouselToFeedSlideViewBinder.bind(feedPromotion); } /** * 레이아웃과 NativeAd / FeedPromotion 간의 연결을 해제 */ fun unbind() { this.nativeAdViewBinder.unbind(); this.carouselToFeedSlideViewBinder.unbind(); } } }iii. 데이터에
FeedPromotion이 있으면 UI에 정상적으로 표시되는지 확인하세요. -
액티비티(
NativeCarouselActivity)를 구현하세요.단, 구현 시 광고 데이터를 어댑터에 할당하는 시점을 기준으로 광고가 있는 경우, 마지막에
FeedPromotion을 붙여 넣도록 구현해야 합니다. 아래 코드의if블록을 참고하세요.public class NativeCarouselActivity extends AppCompatActivity { .... /** * NativeAd 배열을 Carousel에 채워넣을 CarouselItem으로 변환하는 함수 * * @param nativeAds: Carousel에 표시할 광고 객체 배열 * * Carousel To Feed Slide를 원하는 위치에 추가하세요. 광고가 비어있지 않으면 마지막 페이지에 Carousel To Feed Slide를 추가해야 합니다. */ private List<CarouselItem> buildCarouselItems(final Collection<NativeAd> nativeAds) { List<CarouselItem> items = new ArrayList<>(); for (final NativeAd nativeAd : nativeAds) { items.add(new CarouselItem.NativeAdItem(nativeAd)); } if (!items.isEmpty()) { items.add(new CarouselItem.CarouselToFeedSlideItem( new FeedPromotionFactory(unitId).buildForCarousel() )); } return items; } }
피드 엔트리 포인트
캐러셀에서 피드로 진입할 수 있는 UI인 엔트리 포인트(Carousel To Feed Link)를 캐러셀의 하단에 구현해야 합니다.

피드 엔트리 포인트를 구현하려면 다음의 절차를 따르세요.
-
캐러셀로 사용할 RecyclerView 아래에
FeedEntryView를 추가하세요..... <androidx.recyclerview.widget.RecyclerView android:id="@+id/carousel" .... /> <com.buzzvil.buzzad.benefit.presentation.feed.entrypoint.FeedEntryView android:id="@+id/toFeedLink" app:buzzvilFeedEntryViewName="carousel_to_feed_link" ....> </com.buzzvil.buzzad.benefit.presentation.feed.entrypoint.FeedEntryView> -
FeedEntryView를 구현하세요. 다음은 간단한 텍스트와 아이콘을 추가한 예시입니다.<com.buzzvil.buzzad.benefit.presentation.feed.entrypoint.FeedEntryView app:buzzvilFeedEntryViewName="carousel_to_feed_link" ....> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView style="@style/NativeCarouselToFeedLink" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="포인트 더 받으러 가기" /> <ImageView android:layout_width="16dp" android:layout_height="16dp" android:scaleType="centerInside" android:src="@drawable/ic_chevron_right" /> </LinearLayout> </com.buzzvil.buzzad.benefit.presentation.feed.entrypoint.FeedEntryView> -
광고 로딩 요청에 대한 응답 상태에 따른 피드 엔트리 포인트의 표시 여부를 설정하세요.
-
캐러셀 및 피드 엔트리 포인트 미표시: 광고가 아직 로드되지 않은 경우, 오류가 발생하는 경우, 광고가 없는 경우
-
캐러셀 및 피드 엔트리 포인트 표시: 보여줄 광고가 있는 경우
public class NativeCarouselActivity extends AppCompatActivity { .... private void onError() { // 오류가 발생하면 지면을 표시하지 않습니다 binding.placement.setVisibility(View.GONE); .... } private void onEmpty() { // 보여줄 광고가 없으면 지면을 표시하지 않습니다 binding.placement.setVisibility(View.GONE); .... } private void onAdsLoaded(final Collection<NativeAd> nativeAds) { binding.placement.setVisibility(View.VISIBLE); .... } }.... <androidx.constraintlayout.widget.Group android:id="@+id/placement" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="gone" app:constraint_referenced_ids="carousel,toFeedLink" /> ....
광고 아이템의 높이 차이와 상관 없이 피드 엔트리 포인트 위치 고정하기
각 광고 아이템의 설명 텍스트(ad_description_text) 길이 차이로 인해 라인 수가 상이하면 각 슬라이드의 피드 엔트리 포인트의 위치가 계속 변경되는 현상이 발생할 수 있습니다. 이러한 현상의 발생을 방지하기 위해 광고 설명 텍스트를 표시하는 뷰의 lines 값을 고정하여 항상 일정한 위치를 유지할 수 있습니다.
다음은 광고 설명 텍스트를 표시하는 뷰의 lines 값을 2로 설정한 예시입니다.
....
<TextView
android:id="@+id/ad_description_text"
android:ellipsize="end"
android:lines="2"
....
/>
캐러셀의 부가 기능 구현하기
무한 루프 구현하기
캐러셀에서 유한한 아이템을 끊임 없이 스크롤할 수 있는 무한 루프 기능을 구현할 수 있습니다. 캐러셀의 무한 루프를 구현하는 방법는 매우 다양하나, 이 가이드에서는 Adapter의 getItemCount()가 매우 큰 값을 반환하게 하는 가장 간단한 방법을 제시합니다.
무한 루프를 구현하려면 다음의 절차를 따르세요.
-
어댑터(
CarouselAdapter)가 파라미터를 받도록 변경하세요.class CarouselAdapter extends ListAdapter<CarouselItem, CarouselAdapter.ViewHolder> { private final boolean isInfiniteLoopEnabled; .... public CarouselAdapter(final boolean isInfiniteLoopEnabled) { super(new CarouselDiff()); this.isInfiniteLoopEnabled = isInfiniteLoopEnabled; } .... } -
getItemCount()와getItem()의 구현을 변경하세요.
-
getItemCount(): RecyclerView가 무한한 데이터를 가진 것처럼 표시되도록,isInfiniteLoopEnabled가true이고 보여줄 아이템이 있는 경우에는Integer.MAX_VALUE를 반환하도록 변경하세요. -
getItem():super.getItemCount()를 통해 얻은 실제 데이터 값으로 무한 루프의position을 나누어 실제 index 값을 획득하도록 변경하세요.class CarouselAdapter extends ListAdapter<CarouselItem, CarouselAdapter.ViewHolder> { .... @Override public int getItemCount() { final int actualItemCount = super.getItemCount(); if (isInfiniteLoopEnabled && actualItemCount > 0) { // 무한 루프를 쉽게 구현하는 방법으로 매우 큰 수를 여기서 반환합니다. return Integer.MAX_VALUE; } return actualItemCount; } @Override public CarouselItem getItem(final int position) { int newPosition; if (isInfiniteLoopEnabled) { // 무한 루프인 경우의 position은 매우 큰 수이므로 실제 아이템 수로 나눈 나머지를 사용합니다 newPosition = position % super.getItemCount(); } else { newPosition = position; } return super.getItem(newPosition); } .... }
-
액티비티(
NativeCarouselActivity)에CarouselAdapter(isInfiniteLoopEnabled)를 추가하세요.public class NativeCarouselActivity extends AppCompatActivity { .... // 무한 루프를 사용할지 설정 private boolean isInfiniteLoopEnabled = true; .... @Override public void onCreate(final Bundle savedInstanceState) { .... adapter = new CarouselAdapter(isInfiniteLoopEnabled); .... } .... }
첫번째 광고 앞에 마지막 광고를 부분적으로 노출하기
무한 루프 기능을 적용하는 경우, 첫번째 광고 아이템의 왼쪽에 마지막 광고 아이템을 부분적으로 노출하여 사용자가 좌우 양방향으로 스크롤할 수 있음을 알려줄 수 있습니다.
다음의 예시를 참고하여 광고 아이템 목록의 중간이 보여지도록 배열 크기 * 적당히 큰 수로 위치를 변경하세요.
public class NativeCarouselActivity extends AppCompatActivity {
....
private void onAdsLoaded(final Collection<NativeAd> nativeAds) {
....
final List<CarouselItem> items = buildCarouselItems(nativeAds);
adapter.submitList(items);
if (infiniteLoop) {
final RecyclerView.LayoutManager layoutManager = binding.carousel.getLayoutManager();
if (layoutManager != null) {
// item.size(): 첫번째 광고가 보이고, 그 앞에 마지막 아이템이 살짝 보이기 위해 이 값을 기준으로 합니다.
// 10000: 사용자가 앞으로 계속 스크롤을 하여도 무한루프인 것처럼 느낄 수 있도록 적당히 큰 수를 곱합니다.
layoutManager.scrollToPosition(items.size() * 10000);
}
}
....
}
....
}
광고 이벤트 리스너 등록하기
캐러셀에 포함된 광고가 사용자에게 노출되거나 사용자가 클릭하는 등의 광고 이벤트가 발생하는 시점에 특정 동작을 추가할 수 있습니다.
광고 이벤트 리스너를 등록하려면 다음의 절차를 따르세요.
-
NativeAd객체에NativeAdEventListener를 추가하세요.public class NativeCarouselActivity extends AppCompatActivity { .... private NativeAdEventListener nativeAdEventListener = new NativeAdEventListener() { @Override public void onImpressed(final NativeAd nativeAd) { } @Override public void onClicked(final NativeAd nativeAd) { } @Override public void onRewardRequested(final NativeAd nativeAd) { } @Override public void onRewarded( final NativeAd nativeAd, final RewardResult nativeAdRewardResult ) { } @Override public void onParticipated(final NativeAd nativeAd) { } }; .... } -
NativeAd에 이전 단계에서 등록한 리스너(NativeAdEventListener)를 등록하세요.public class NativeCarouselActivity extends AppCompatActivity { .... private void onAdsLoaded(final Collection<NativeAd> nativeAds) { .... for (final NativeAd nativeAd : nativeAds) { nativeAd.addNativeAdEventListener(nativeAdEventListener); } .... } }
광고 아이템 크기 줄이기
LinearLayoutManager의 checkLayoutParams를 조정하여 슬라이드의 너비를 줄일 수 있습니다. 이를 통해 광고 아이템의 크기를 줄이고 앞뒤 광고를 부분적으로 노출해 사용자의 스크롤을 유도할 수 있습니다.
다음은 광고 아이템의 크기를 캐러셀(RecyclerView) 너비를 기준으로 80%만 차지하도록 줄이는 예시입니다.
public class NativeCarouselActivity extends AppCompatActivity {
....
// 화면 폭에 대한 Carousel 아이템의 폭 비율
private final float itemWidthPercentOfScreen = 0.8f;
// LinearLayoutManager를 사용하고 HORIZONTAL로 설정하여 수평으로 일렬로 정렬된 레이아웃을 사용합니다
private LinearLayoutManager layoutManager = new LinearLayoutManager(
this,
HORIZONTAL,
false
) {
// Carousel 아이템의 폭을 설정한 비율에 맞게 변경합니다.
@Override
public boolean checkLayoutParams(final RecyclerView.LayoutParams lp) {
lp.width = Math.round(getWidth() * itemWidthPercentOfScreen);
return true;
}
};
....
}
광고 아이템의 크기를 캐러셀(RecyclerView) 너비와 상관 없이 줄이려면 다음의 예시를 참고하세요.
public class NativeCarouselActivity extends AppCompatActivity {
....
// 화면 폭에 대한 Carousel 아이템의 폭 차이
private final int itemWidthDifferenceFromScreenDp = 76;
// LinearLayoutManager를 사용하고 HORIZONTAL로 설정하여 수평으로 일렬로 정렬된 레이아웃을 사용합니다
private final LinearLayoutManager layoutManager = new LinearLayoutManager(
this,
HORIZONTAL,
false
) {
// Carousel 아이템의 폭을 설정한 비율에 맞게 변경합니다
@Override
public boolean checkLayoutParams(final RecyclerView.LayoutParams lp) {
lp.width = getWidth() - dpToPx(itemWidthDifferenceFromScreenDp);
return true;
}
}
....
}
광고 아이템 사이의 여백 설정하기
RecyclerView에서 광고 아이템 사이의 여백을 설정하려면 다양한 방법을 적용할 수 있습니다. 이 가이드에서는 ItemDecoration을 사용하는 방법을 제시합니다. 다음의 절차를 따르세요.
-
다음 예시를 참고하여 RecylerView에서 사용할
ItemDecoration을 선언하세요./** * 아이템 사이의 간격을 넣기 위한 ItemDecoration */ class PaddingDividerDecoration extends RecyclerView.ItemDecoration { private final int paddingDp; /** * @param paddingDp: 아이템 간의 간격, 단위는 dp */ public PaddingDividerDecoration(final int paddingDp) { this.paddingDp = paddingDp; } @Override public void getItemOffsets( final Rect outRect, final View view, final RecyclerView parent, final RecyclerView.State state ) { // 여백을 한 쪽만 설정하면 PagerSnapHelper가 약간 어긋나게 동작하므로, 양쪽에 동일하게 여백을 넣습니다. outRect.left = dpToPx(paddingDp / 2); outRect.right = dpToPx(paddingDp / 2); } private int dpToPx(final int dp) { return (int) (dp * Resources.getSystem().getDisplayMetrics().density); } } -
캐러셀을 초기화할 때 이전 단계에서 선언한
ItemDecoration을 추가하세요.class NativeCarouselActivity : AppCompatActivity() { // Carousel 아이템 간의 사이 간격 private val itemPaddingDp = 16 .... private fun initCarousel() { .... // 아이템 간에 여백을 넣는 Decoration 추가 binding.carousel.addItemDecoration(PaddingDividerDecoration(itemPaddingDp)) } .... }
앞뒤 광고 아이템을 부분적으로 노출하기
광고 아이템의 크기를 줄이거나 사이 여백을 설정한 후에 앞뒤 광고 아이템이 부분적으로 노출되던 레이아웃이 변경될 수 있습니다. 이로 인해 사용자가 캐러셀에서 광고 아이템을 스크롤 할 수 있음을 인식하지 못할 수도 있습니다. 이러한 문제를 해결하기 위해 앞뒤 광고 아이템을 부분적으로 노출하도록 설정할 수 있습니다.
앞뒤 광고 아이템을 부분적으로 노출하려면 RecyclerView에 android:clipToPadding을 false로 설정한 후 paddingHorizontal을 추가하세요.
....
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/carousel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:paddingHorizontal="32dp" />
....