Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

개요

Feed의 구성 컴포넌트는 다음과 같습니다.

...

목차

Table of Contents
minLevel1
maxLevel71
exclude개요
Note

이하 가이드에서 커스터마이징을 위해 구현 클래스를 정의합니다. 구현하는 클래스는 아래의 조건을 충족해야 합니다. 아래 조건을 충족하지 않는 경우 커스터마이징이 적용되지 않습니다.

  • 구현 클래스는 내부 클래스(Inner 클래스)가 아니어야 합니다.

  • 만일 내부 클래스로 생성을 해야 할 경우, public 정적(static) 클래스로 구현해야 합니다.

툴바(Toolbar)

<< 툴바 확대 이미지>>

Feed 툴바 영역의 디자인을 변경할 수 있습니다. 툴바 영역을 UI를 변경하는 방법은 2가지입니다. 아래 2가지 방법 중 하나를 선택하여 연동합니다.

  1. SDK에서 기본으로 제공하는 UI를 이용하는 방법
    SDK에서 기본으로 제공하는 UI를 수정하여 간단히 타이틀 혹은 배경색을 변경할 수 있습니다.

  2. 직접 구현한 Custom View를 이용하는 방법
    SDK에서 기본으로 제공하는 UI를 이용하지 않고 직접 구현하여 변경할 수 있습니다.

1. SDK에서 기본으로 제공하는 UI를 이용하는 방법

FeedToolbarHolde의 상속 클래스를 구현하고 SDK에서 기본으로 제공하는 UI(FeedActivityToolbar)를 이용하는 변경 예시는 아래와 같습니다.

Code Block
languagejava
public class YourFeedToolbarHolder implements FeedToolbarHolder {
    private FeedActivityToolbar toolbar;

    @Override
    public View getView(final Activity activity, @NonNull final String unitId) {
        this.toolbar = new FeedActivityToolbar(activity, unitId);
        toolbar.setTitle("BuzzAd Feed"); // 타이틀 변경
        toolbar.setBackgroundColor(Color.parseColor("#1290FF")); // 배경색 변경
        return toolbar;
    }

    @Override
    public void onTotalRewardUpdated(int totalReward) {
    }
}
Code Block
languagejava
final FeedConfig feedConfig = new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID")
      .feedToolbarHolderClass(YourFeedToolbarHolder.class)
      .build();

2. 직접 구현한 Custom View를 이용하는 방법

FeedToolbarHolde의 구현 클래스를 구현하고 직접 구현한 View(YourCustomView)를 이용하는 변경 예시는 아래와 같습니다.

Code Block
languagejava
public class YourFeedToolbarHolder implements FeedToolbarHolder {

    @Override
    public View getView(final Activity activity, @NonNull final String unitId) {
        YourCustomView yourCustomView = new YourCustomView();
        return yourCustomView;
    }

    @Override
    public void onTotalRewardUpdated(int totalReward) {
    }
}
Code Block
languagejava
final FeedConfig feedConfig = new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID")
      .feedToolbarHolderClass(YourFeedToolbarHolder.class)
      .build();

직접 구현한 View의 높이가 안드로이드 액티비티의 기본 액션바 높이와 다를 경우, 직접 구현한 View가 정상적으로 보이지 않을 수 있습니다. 이 경우에는 액티비티에 Theme 을 설정하여 액션바 높이를 수정해야 합니다.

Code Block
languagexml
// AndroidManifest.xml

...

<activity
    android:name="com.buzzvil.buzzad.benefit.presentation.feed.FeedBottomSheetActivity"
    android:theme="@style/YourActivityTheme"
    tools:replace="android:theme"/>
    
...
Code Block
languagexml
// styles.xml
<style name="YourActivityTheme" parent= ...>
    <item name="actionBarSize">DESIRED_ACTION_BAR_HEIGHT</item>
</style>

헤더

<< 헤더 확대 이미지>>

Feed 헤더 영역을 자유로이 활용할 수 있습니다. 예를 들어, Feed 영역을 설명하는 공간으로도 활용할 수 있습니다.

헤더 영역을 수정하는 방법은 아래와 같습니다. 새 레이아웃(your_feed_header_layout)을 사용하는 구현 클래스를 작성합니다. 그리고, FeedConfigFeedHeaderViewAdapter에 작성한 구현 클래스를 설정합니다.

Code Block
languagejava
public class CustomFeedHeaderViewAdapter implements FeedHeaderViewAdapter {
    @Override
    public View onCreateView(final Context context, final ViewGroup parent) {
        final LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        return inflater.inflate(R.layout.your_feed_header_layout, parent, false);
    }

    @Override
    public void onBindView(final View view, final int reward) {
        // Display total reward on the header if needed.
        final View rewardLayout = view.findViewById(R.id.rewardLayout);
        if (reward == 0) {
            rewardLayout.setVisibility(View.GONE);
        } else {
            rewardLayout.setVisibility(View.VISIBLE);
            final TextView rewardTextView = view.findViewById(R.id.rewardText);
            final String rewardText = view.getContext().getString(R.string.bz_feed_header_view_reward_text, reward);
            rewardTextView.setText(rewardText);
        }
    }
    
    @Override 
    public void onDestroyView() {
        // Use this this callback for clearing memory 
    }
}
Code Block
languagejava
final FeedConfig feedConfig = new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID")
      .feedHeaderViewAdapterClass(CustomFeedHeaderViewAdapter.class)
      .build();

...

목차

개요

본 가이드에서는 BuzzAd Android SDK에서 제공하는 UI의 구성을 지키며 디자인을 변경하기 위한 방법을 안내합니다. 추가적인 디자인 변경을 원하시는 경우에는 고급 설정에서 UI를 자체 구현하는 방법으로 진행할 수 있습니다.

탭 UI 변경

...

아래의 방법으로 탭의 디자인을 수정할 수 있습니다.

필터 UI 변경

...

아래의 방법으로 필터의 디자인을 수정할 수 있습니다. 필터의 색상을 변경하기 위해서는 https://buzzvil.atlassian.net/wiki/spaces/BDG/pages/2164329086/ver%2B2.23.x%2B9.#PrimaryColor-%EB%B3%80%EA%B2%BD을 참고하시기 바랍니다.

...

광고 아이템 커스터마이징: 일반 광고

<<일반 광고과 쇼핑광고이미지 (일반광고 강조)>>

버즈빌 SDK에서 제공하는 광고는 일반 광고와 쇼핑 적립 광고가 있습니다. 다음은 일반 광고의 디자인을 변경하는 방법을 설명합니다.

일반 광고용 NativeAdView의 규격에 맞는 레이아웃(your_feed_ad.xml)을 구현합니다.

Code Block
// your_feed_ad.xml

<com.buzzvil.buzzad.benefit.presentation.nativead.NativeAdView
    android:id="@+id/native_ad_view" ...>
    
    // MediaView와 CtaView는 NativeAdView의 하위 컴포넌트로 구현해야합니다.
    <LinearLayout ... >
        <com.buzzvil.buzzad.benefit.presentation.media.MediaView
            android:id="@+id/mediaView" ... />
        <TextView
            android:id="@+id/textTitle" ... />
        <TextView
            android:id="@+id/textDescription" ... />
        <ImageView
            android:id="@+id/imageIcon" ... />
        <com.buzzvil.buzzad.benefit.presentation.media.CtaView
            android:id="@+id/ctaView" ... />
    </LinearLayout>
    
</com.buzzvil.buzzad.benefit.presentation.nativead.NativeAdView>

AdsAdapter의 상속 클래스를 구현합니다. 구현한 상속 클래스의 onCreateViewHolder에서 your_feed_ad.xml을 사용하여 NativeAdView를 생성합니다. 그리고 FeedConfig에 구현한 YourAdsAdapter를 설정합니다.

CTA 버튼 커스터마이징은 https://buzzvil.atlassian.net/wiki/spaces/BDG/pages/2270135722/ver+2.25.x+9.#CTA-%EB%B3%80%EA%B2%BD을 참고하시기 바랍니다.

Code Block
languagejava
public class YourAdsAdapter extends AdsAdapter<AdsAdapter.NativeAdViewHolder> {

    @Override
    public NativeAdViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        final NativeAdView feedNativeAdView = (NativeAdView) inflater.inflate(R.layout.your_feed_ad, parent, false);
        return new NativeAdViewHolder(feedNativeAdView);
    }

    @Override
    public void onBindViewHolder(NativeAdViewHolder holder, NativeAd nativeAd) {
        final NativeAdView view = (NativeAdView) holder.itemView;

        final Ad ad = nativeAd.getAd();
        
        // create ad component
        final MediaView mediaView = view.findViewById(R.id.mediaView);
        final LinearLayout titleLayout = view.findViewById(R.id.titleLayout);
        final TextView titleView = view.findViewById(R.id.textTitle);
        final ImageView iconView = view.findViewById(R.id.imageIcon);
        final TextView descriptionView = view.findViewById(R.id.textDescription);
        final CtaView ctaView = view.findViewById(R.id.ctaView);
        final CtaPresenter ctaPresenter = new CtaPresenter(ctaView); // CtaView should not be null

        // data binding 
        ctaPresenter.bind(nativeAd);

        if (mediaView != null) {
            mediaView.setCreative(ad.getCreative());
            mediaView.setVideoEventListener(new VideoEventListener() {
                // Override and implement methods

                @Override
                public void onVideoStarted() {}

                ...생략...
          
            });
        }
        
        if (titleView != null) {
            titleView.setText(ad.getTitle());
        }

        if (iconView != null) {
            ImageLoader.getInstance().displayImage(ad.getIconUrl(), iconView);
        }
        if (descriptionView != null) {
            descriptionView.setText(ad.getDescription());
        }

        // clickableViews에 추가된 UI 컴포넌트를 클릭하면 광고 페이지로 이동합니다.
        final Collection<View> clickableViews = new ArrayList<>();
        clickableViews.add(ctaView);
        clickableViews.add(mediaView);
        clickableViews.add(titleLayout);
        clickableViews.add(descriptionView);

        view.setMediaView(mediaView);
        view.setClickableViews(clickableViews);
        view.setNativeAd(nativeAd);
        
        // 광고 콜백 이벤트를 수신할 수 있습니다. 
        view.addOnNativeAdEventListener(new NativeAdView.OnNativeAdEventListener() {
            
            @Override
            public void onImpressed(final @NonNull NativeAdView view, final @NonNull NativeAd nativeAd) {

            }

            @Override
            public void onClicked(@NonNull NativeAdView view, @NonNull NativeAd nativeAd) {
                ctaPresenter.bind(nativeAd);
            }

            @Override
            public void onRewardRequested(@NonNull NativeAdView view, @NonNull NativeAd nativeAd) {

            }

            @Override
            public void onRewarded(@NonNull NativeAdView nativeAdView, @NonNull NativeAd nativeAd, @Nullable RewardResult rewardResult) {

            }

            @Override
            public void onParticipated(final @NonNull NativeAdView view, final @NonNull NativeAd nativeAd) {
                ctaPresenter.bind(nativeAd);
            }
        });
    }
}
Code Block
languagejava
final FeedConfig feedConfig = new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID")
      .adsAdapterClass(YourAdsAdapter.class)
      .build();

광고 아이템 커스터마이징: 쇼핑 적립 광고

<<일반 광고과 쇼핑광고이미지 (일반광고 강조)>>

Info

일반 광고의 커스터마이징을 참고하시기 바랍니다.

버즈빌 SDK에서 제공하는 광고는 일반 광고와 쇼핑 적립 광고가 있습니다. 아래 가이드는 쇼핑 적립 광고의 디자인을 변경하는 방법을 설명합니다. 쇼핑 적립 광고는 일반 광고에 비해 많은 정보를 제공합니다.

쇼핑 적립 광고용 NativeAdView의 규격에 맞는 레이아웃(your_feed_ad_cps.xml)을 구현합니다. 일반 광고용 레이아웃에 없는 priceText, originalPriceText, discountPercentageText, categoryText 가 있습니다.

Code Block
// your_feed_ad_cps.xml

<?xml version="1.0" encoding="utf-8"?>
<com.buzzvil.buzzad.benefit.presentation.nativead.NativeAdView
    android:id="@+id/native_ad_view"
    ...생략... >
    <LinearLayout
        ...생략... >
        
        // MediaView와 CtaView는 NativeAdView의 하위 컴포넌트로 구현해야합니다.
        
        <com.buzzvil.buzzad.benefit.presentation.media.MediaView
            android:id="@+id/mediaView"
            ...생략... />
            
        ...생략...
    
        <TextView
            android:id="@+id/priceText"
            ...생략... />
        <TextView
            android:id="@+id/originalPriceText"
            ...생략... />
        <TextView
            android:id="@+id/discountPercentageText"
            ...생략... />
        <TextView
            android:id="@+id/categoryText"
            ...생략... />
            
        ...생략...
        
    </LinearLayout>
    ...생략...
</com.buzzvil.buzzad.benefit.presentation.nativead.NativeAdView>

AdsAdapter의 상속 클래스를 구현합니다. 구현한 상속 클래스의 onCreateViewHolder에서 your_feed_ad_cps.xml을 사용하여 NativeAdView를 생성합니다. 그리고 FeedConfig에 구현한 YourCPSAdsAdapter를 설정합니다.

CTA 버튼 커스터마이징은 https://buzzvil.atlassian.net/wiki/spaces/BDG/pages/2270135722/ver+2.25.x+9.#CTA-%EB%B3%80%EA%B2%BD 을 참고하시기 바랍니다.

Code Block
languagejava
public class YourCPSAdsAdapter extends AdsAdapter<AdsAdapter.NativeAdViewHolder> {

    @Override
    public NativeAdViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        final NativeAdView feedNativeAdView = (NativeAdView) inflater.inflate(R.layout.your_feed_ad_cps, parent, false);
        return new NativeAdViewHolder(feedNativeAdView);
    }

    @Override
    public void onBindViewHolder(NativeAdViewHolder holder, NativeAd nativeAd) {
        final NativeAdView view = (NativeAdView) holder.itemView;
        final Ad ad = nativeAd.getAd();
        
        // create ad component
        ...생략...
        final TextView priceText = view.findViewById(R.id.discountedPriceText);
        final TextView originalPriceText = view.findViewById(R.id.originalPriceText);
        final TextView discountPercentageText = view.findViewById(R.id.discountPercentageText);
        final TextView categoryText = view.findViewById(R.id.categoryText);

        // data binding 
        ...생략...
        final Product product = ad.getProduct();
        if (product != null) {
            if (product.getDiscountedPrice() != null) {
                // 할인이 있는 쇼핑 광고
                originalPriceText.setPaintFlags(originalPriceText.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
                int percentage = 0;
                if (product.getPrice() > product.getDiscountedPrice()) {
                    percentage = Math.round(((product.getPrice() - product.getDiscountedPrice()) / product.getPrice() * 100));
                }
                if (percentage > 0) {
                    priceText.setText(getCommaSeparatedPrice(product.getDiscountedPrice().longValue()));
                    originalPriceText.setText(getCommaSeparatedPrice((long) product.getPrice()));
                    discountPercentageText.setText(String.format(Locale.ROOT, "%d%%", percentage));
                    discountPercentageText.setVisibility(View.VISIBLE);
                } else {
                    priceText.setText(getCommaSeparatedPrice((long) product.getPrice()));
                    originalPriceText.setText("");
                    discountPercentageText.setVisibility(View.GONE);
                }
            } else {
                // 할인이 없는 쇼핑 광고
                priceText.setText(getCommaSeparatedPrice((long) product.getPrice()));
                originalPriceText.setText("");
                discountPercentageText.setVisibility(View.GONE);
            }
            categoryText.setText(product.getCategory());
            if (!TextUtils.isEmpty(product.getCategory())) {
                categoryText.setVisibility(View.VISIBLE);
            }
        }

        final Collection<View> clickableViews = new ArrayList<>();
        clickableViews.add(ctaView);
        clickableViews.add(mediaView);
        clickableViews.add(descriptionView);

        view.setMediaView(mediaView);
        view.setClickableViews(clickableViews);
        view.setNativeAd(nativeAd);
        
        ...생략...
    }

    private String getCommaSeparatedPrice (long price){
        return String.format(Locale.getDefault(), "₩%,d", price);
    }
}
Code Block
languagejava
final FeedConfig feedConfig = new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID")
      .cpsAdsAdapterClass(YourCPSAdsAdapter.class)
      .build();

베이스 리워드 지급 안내 UI 커스터마이징

...

사용자가 Feed 지면에 접근하면 일정 주기로 베이스 리워드를 지급합니다. 베이스 리워드 지급 알림 UI는 위의 이미지와 같습니다. 베이스 리워드 지급 알림 UI를 수정하여 좀 더 사용자 경험을 개선할 수 있습니다. 다음은 베이스 리워드 지급 알림 UI 를 수정하는 예시입니다.

Code Block
languagekotlin
public class YourFeedFeedbackHandler extends DefaultFeedFeedbackHandler {
   @NotNull
   public View getBaseRewardNotificationView(@NotNull Context context, int reward) {
        View view = LayoutInflater.from(context).inflate(R.layout.your_layout, null);  
        return view
   }
}
Code Block
languagejava
final FeedConfig feedConfig = new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID")
      .feedFeedbackHandler(YourFeedFeedbackHandler.class)
      .build();

Pop 활성화 버튼

...

테마 적용을 참고하시기 바랍니다.

Pop 활성화 버튼

...

Pop 활성화 버튼의 디자인은 아래 가이드에 따라 수정할 수 있습니다.

  • 활성화 버튼의 색상과 아이콘은 테마 적용을 통해 변경할 수 있습니다.

  • 활성화 버튼의 문구는 DefaultOptInAndShowPopButtonHandler의 상속 클래스에서 설정합니다. 상속 클래스를 작성하고 FeedConfig에 설정합니다.

    Code Block
    languagejava
    class YourOptInAndShowPopButtonHandler extends DefaultOptInAndShowPopButtonHandler {
        // 활성화 버튼에 보여지는 문구입니다.
        @Override
        public String getOptInAndShowPopButtonText(Context context) {
            return "YOUR_BUTTON_TEXT"
        }
    }
    Code Block
    languagejava
    final FeedConfig feedConfig = new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID")
            .optInAndShowPopButtonHandler(CustomOptInAndShowPopButtonHandler.class)
            .build();