...
툴바(Toolbar)
<< 툴바 확대 이미지>>
FeedToolbarHolder.getView에 새로운 View로 반환하여 Feed 툴바 영역의 디자인을 변경할 수 있습니다. 툴바 영역을 UI를 변경하는 방법은 2가지입니다. 아래 2가지 방법 중 하나를 선택하여 연동합니다.
SDK에서 기본으로 제공하는
...
UI를 이용하는 방법
SDK에서 기본으로 제공하는 UI를 수정하여 간단히 타이틀 혹은 배경색을 변경할 수 있습니다.
...
직접 구현한 Custom View를 이용하는 방법
SDK에서 기본으로 제공하는 UI를 이용하지 않고 직접 구현하여 변경할 수 있습니다.
...
1. SDK에서 기본으로 제공하는 UI를 이용하는 방법
FeedToolbarHolde의 상속 클래스를 구현하고 SDK에서 기본으로 제공하는 UI(FeedActivityToolbar
)를 이용하는 변경 예시는 아래와 같습니다.
Code Block | ||
---|---|---|
| ||
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 | ||
---|---|---|
| ||
final FeedConfig feedConfig = new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID") .feedToolbarHolderClass(YourFeedToolbarHolder.class) .build(); |
...
2. 직접 구현한 Custom View를 이용하는 방법
FeedToolbarHolde의 구현 클래스를 구현하고 직접 구현한 View(YourCustomView
)를 이용하는 변경 예시는 아래와 같습니다.
Code Block | ||
---|---|---|
| ||
// AndroidManifest.xml ...생략... <activitypublic class YourFeedToolbarHolder implements FeedToolbarHolder { @Override android:name="com.buzzvil.buzzad.benefit.presentation.feed.FeedBottomSheetActivity" android:theme="@style/YourActivityTheme" tools:replace="android:theme"/>public View getView(final Activity activity, @NonNull final String unitId) { ...생략... | ||
Code Block | ||
| ||
// styles.xml <style name="YourActivityTheme" parent=...> YourCustomView yourCustomView = new YourCustomView(); ...생략... return yourCustomView; } <item name="actionBarSize">DESIRED_ACTION_BAR_HEIGHT</item> @Override public ...생략... </style> |
헤더
<< 헤더 확대 이미지>>
Feed 헤더 영역을 자유로이 활용할 수 있습니다. 예를 들어, Feed 영역을 설명하는 공간으로도 활용할 수 있습니다.
...
void onTotalRewardUpdated(int totalReward) {
}
} |
Code Block | ||
---|---|---|
| ||
publicfinal classFeedConfig CustomFeedHeaderViewAdapterfeedConfig implements= FeedHeaderViewAdapter { @Override public View onCreateView(final Context context, final ViewGroup parent) { final LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID") .feedToolbarHolderClass(YourFeedToolbarHolder.class) 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 build(); |
직접 구현한 View의 높이가 안드로이드 액티비티의 기본 액션바 높이와 다를 경우, 직접 구현한 View가 정상적으로 보이지 않을 수 있습니다. 이 경우에는 액티비티에 Theme 을 설정하여 액션바 높이를 수정해야 합니다.
Code Block | ||
---|---|---|
| ||
// AndroidManifest.xml
...
<activity
android:name="com.buzzvil.buzzad.benefit.presentation.feed.FeedBottomSheetActivity"
android:theme="@style/YourActivityTheme"
tools:replace="android:theme"/>
... |
Code Block | ||
---|---|---|
| ||
// styles.xml
<style name="YourActivityTheme" parent= ...>
<item name="actionBarSize">DESIRED_ACTION_BAR_HEIGHT</item>
</style> |
헤더
<< 헤더 확대 이미지>>
Feed 헤더 영역을 자유로이 활용할 수 있습니다. 예를 들어, Feed 영역을 설명하는 공간으로도 활용할 수 있습니다.
헤더 영역을 수정하는 방법은 아래와 같습니다. 새 레이아웃(your_feed_header_layout
)을 사용하는 구현 클래스를 작성합니다. 그리고, FeedConfig
에 FeedHeaderViewAdapter
에 작성한 구현 클래스를 설정합니다.
Code Block | ||
---|---|---|
| ||
public class CustomFeedHeaderViewAdapter implements FeedHeaderViewAdapter { @Override public View onCreateView(final Context context, final ViewGroup parent) { final LayoutInflater inflater = rewardLayout.setVisibility(View.VISIBLE(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); final TextView rewardTextView = view.findViewByIdreturn inflater.inflate(R.id.rewardTextlayout.your_feed_header_layout, parent, false); } @Override final String rewardTextpublic =void view.getContext().getString(R.string.bz_feed_header_view_reward_text, reward); onBindView(final View view, final int reward) { // Display rewardTextView.setText(rewardText); total reward on the header if needed. } }final View rewardLayout = view.findViewById(R.id.rewardLayout); @Override if (reward public void onDestroyView(== 0) { // Use this this callback for clearing memory rewardLayout.setVisibility(View.GONE); } } | ||
Code Block | ||
| ||
final FeedConfig feedConfig = new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID") .feedHeaderViewAdapterClass(CustomFeedHeaderViewAdapter.class)else { rewardLayout.setVisibility(View.VISIBLE); final TextView rewardTextView = view.findViewById(R.id.rewardText); final .build(); |
탭
아래의 방법으로 탭의 디자인을 수정할 수 있습니다.
탭의 문구는 FeedConfig에서 설정할 수 있습니다.
탭의 색상은 https://buzzvil.atlassian.net/wiki/spaces/BDG/pages/2164329086/ver%2B2.23.x%2B9.#PrimaryColor-%EB%B3%80%EA%B2%BD 를 통해 변경할 수 있습니다.
...
Code Block | ||
---|---|---|
| ||
final FeedConfig feedConfig = new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID")String rewardText = view.getContext().getString(R.string.bz_feed_header_view_reward_text, reward); rewardTextView.tabUiEnabledsetText(truerewardText); // set tabUiEnabled to true } } @Override public void .tabTextArray(new String[] { FIRST_TAB_NAME, SECOND_TAB_NAME })onDestroyView() { // 탭에 들어갈 문구Use this this callback for clearing memory } .build(); |
필터
...
} |
Code Block | ||
---|---|---|
| ||
final FeedConfig feedConfig = new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID")
.feedHeaderViewAdapterClass(CustomFeedHeaderViewAdapter.class)
.build(); |
탭
...
아래의 방법으로 탭의 디자인을 수정할 수 있습니다. 필터의 색상을 변경하기 위해서는
...
광고 아이템 커스터마이징: 일반 광고
<<일반 광고과 쇼핑광고이미지 (일반광고 강조)>>
버즈빌 SDK에서 제공하는 광고는 일반 광고와 쇼핑 적립 광고가 있습니다. 다음은 일반 광고의 디자인을 변경하는 방법을 설명합니다.
일반 광고용 NativeAdView의 규격에 맞는 레이아웃(your_feed_ad.xml
)을 구현합니다.
...
를 통해 변경할 수 있습니다.
탭의 문구는 FeedConfig를 설정하여 변경합니다.
Code Block language java final FeedConfig feedConfig = new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID") .tabUiEnabled(true) // set tabUiEnabled to true .tabTextArray(new String[] { FIRST_TAB_NAME, SECOND_TAB_NAME }) // 탭에 들어갈 문구 .build();
필터
아래의 방법으로 필터의 디자인을 수정할 수 있습니다. 필터의 색상을 변경하기 위해서는 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/mediaViewnative_ad_view" ...> // MediaView와 CtaView는 NativeAdView의 ...생략하위 컴포넌트로 구현해야합니다. <LinearLayout ... /> <TextView<com.buzzvil.buzzad.benefit.presentation.media.MediaView android:id="@+id/textTitlemediaView" ...생략... /> <TextView android:id="@+id/textDescriptiontextTitle" ... /> <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/22701347222270135722/ver+2.25.x+39.3.#CtaView-(%EB%B2%84%ED%8A%BC)-%EC%BB%A4%EC%8A%A4%ED%84%B0%EB%A7%88%EC%9D%B4%EC%A7%95#CTA-%EB%B3%80%EA%B2%BD을 참고하시기 바랍니다.
Code Block | ||
---|---|---|
| ||
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); } }); } } |
...
AdsAdapter의 상속 클래스를 구현합니다. 구현한 상속 클래스의 onCreateViewHolder에서 your_feed_ad_cps.xml
을 사용하여 NativeAdView를 생성해야 합니다생성합니다. 그리고 FeedConfig에 구현한 YourCPSAdsAdapter
를 설정합니다.
CTA 버튼 커스터마이징은 https://buzzvil.atlassian.net/wiki/spaces/BDG/pages/22701347222270135722/ver+2.25.x+39.3.#CtaView-(%EB%B2%84%ED%8A%BC)-%EC%BB%A4%EC%8A%A4%ED%84%B0%EB%A7%88%EC%9D%B4%EC%A7%95#CTA-%EB%B3%80%EA%B2%BD 을 참고하시기 바랍니다.
Code Block | ||
---|---|---|
| ||
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 { public class YourCPSAdsAdapter extends AdsAdapter<AdsAdapter.NativeAdViewHolder> { @Override public NativeAdViewHolder priceText.setText(getCommaSeparatedPrice((long) product.getPrice())); onCreateViewHolder(ViewGroup parent, int viewType) { final LayoutInflater inflater originalPriceText.setText(""= LayoutInflater.from(parent.getContext()); discountPercentageText.setVisibility(View.GONE); final NativeAdView feedNativeAdView = (NativeAdView) inflater.inflate(R.layout.your_feed_ad_cps, parent, false); } return new NativeAdViewHolder(feedNativeAdView); } } else { @Override public void onBindViewHolder(NativeAdViewHolder holder, NativeAd nativeAd) { // 할인이 없는 쇼핑 광고final NativeAdView view = (NativeAdView) holder.itemView; final Ad priceText.setText(getCommaSeparatedPrice((long) product.getPrice()))ad = nativeAd.getAd(); originalPriceText.setText(""); // create ad component ...생략... final TextView priceText = discountPercentageTextview.setVisibilityfindViewById(ViewR.id.GONEdiscountedPriceText); final TextView originalPriceText }= view.findViewById(R.id.originalPriceText); final TextView discountPercentageText = categoryTextview.setTextfindViewById(product.getCategory())R.id.discountPercentageText); final TextView categoryText if= view.findViewById(!TextUtils.isEmpty(product.getCategory())) {R.id.categoryText); // data binding categoryText.setVisibility(View.VISIBLE); ...생략... }final Product product = ad.getProduct(); } if (product != null) { final Collection<View> clickableViews = new ArrayList<>(); if clickableViews.add(ctaView); (product.getDiscountedPrice() != null) { clickableViews.add(mediaView); clickableViews.add(descriptionView); // 할인이 있는 쇼핑 광고 view.setMediaView(mediaView); view.setClickableViews(clickableViews); originalPriceText.setPaintFlags(originalPriceText.getPaintFlags() | view.setNativeAd(nativeAdPaint.STRIKE_THRU_TEXT_FLAG); ...생략... }int percentage = 0; private String getCommaSeparatedPrice (long price){ returnif String(product.format(Locale.getDefault(), "₩%,d", price);getPrice() > product.getDiscountedPrice()) { } } | ||
Code Block | ||
| ||
final FeedConfig feedConfig = new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID") percentage = Math.round(((product.getPrice() - product.cpsAdsAdapterClassgetDiscountedPrice(YourCPSAdsAdapter.class)) / product.getPrice() .build(); |
CtaView 버튼
2.21 버전 이상에서는 아래 방법보다는 Theme을 활용하는 방법을 권장합니다.
BuzzAd Android SDK에서 제공하는 CtaView UI 및 처리 로직을 사용하지 않고 기획에 맞게 구현할 경우 다음과 같이 진행할 수 있습니다.
Info |
---|
위에서 안내한 AdsAdapter 의 |
Code Block | ||
---|---|---|
| ||
@Override public void onBindViewHolder(NativeAdViewHolder holder, NativeAd nativeAd) {* 100)); final} NativeAdView view = (NativeAdView) holder.itemView; // create adif component(percentage > 0) { ...생략... final YourCtaView ctaView = view.findViewById(R.id.your_cta_view); updateCtaStatus(ctaView, nativeAdpriceText.setText(getCommaSeparatedPrice(product.getDiscountedPrice().longValue())); ...생략... final List<View> clickableViews = new ArrayList<>(); clickableViews.add(customizedCtaView); originalPriceText.setText(getCommaSeparatedPrice((long) product.getPrice())); ...생략... nativeAdView.addOnNativeAdEventListener(new NativeAdView.OnNativeAdEventListener() { ...생략...discountPercentageText.setText(String.format(Locale.ROOT, "%d%%", percentage)); @Override public void onClicked(@NonNull NativeAdView view, @NonNull NativeAd nativeAd) {discountPercentageText.setVisibility(View.VISIBLE); } else updateCtaStatus(ctaView, nativeAd);{ } priceText.setText(getCommaSeparatedPrice((long) product.getPrice())); @Override public void onParticipated(@NonNull NativeAdView view, @NonNull NativeAd nativeAd) { originalPriceText.setText(""); updateCtaStatus(ctaView, nativeAd); discountPercentageText.setVisibility(View.GONE); } }); } // 기획에 따라 수정될 수 있는} 예시 코드입니다. void updateCtaStatus(YourCtaView ctaView, NativeAd nativeAd) { } finalelse String{ callToAction = nativeAd.getAd().getCallToAction(); final int reward = nativeAd.getAvailableReward(); final// int할인이 totalReward없는 = nativeAd.getAd().getReward();쇼핑 광고 final boolean participated = nativeAd.isParticipated(); final boolean isClicked = nativeAd.isClicked(); priceText.setText(getCommaSeparatedPrice((long) product.getPrice())); final boolean isActionType = nativeAdoriginalPriceText.getAdsetText("").isActionType(); if (isClicked && isActionType && !participated) { discountPercentageText.setVisibility(View.GONE); ctaView.setCtaText("참여 확인 중"); } ctaView.setRewardIcon(null); ctaView.setRewardText(nullcategoryText.setText(product.getCategory()); } else { if (totalReward > 0 && participated) {(!TextUtils.isEmpty(product.getCategory())) { ctaViewcategoryText.setRewardIconsetVisibility(R.drawable.your_reward_received_icon);View.VISIBLE); } ctaView.setRewardText(null);} final Collection<View> clickableViews = new ctaView.setCtaText("참여 완료"ArrayList<>(); } else if (reward > 0) {clickableViews.add(ctaView); clickableViews.add(mediaView); ctaViewclickableViews.showRewardImage(R.drawable.your_reward_iconadd(descriptionView); view.setMediaView(mediaView); ctaView.setRewardText(String.format(Locale.US, "+%,d", reward)); view.setClickableViews(clickableViews); ctaView view.setCtaTextsetNativeAd(callToActionnativeAd); } else { ...생략... } ctaView.showRewardImage(null); private String getCommaSeparatedPrice (long price){ return ctaView.setRewardText(null); String.format(Locale.getDefault(), "₩%,d", price); } } |
Code Block | ||
---|---|---|
| ||
final FeedConfig feedConfig = new ctaViewFeedConfig.setCtaText(callToAction);Builder(context, "YOUR_FEED_UNIT_ID") .cpsAdsAdapterClass(YourCPSAdsAdapter.class) } } }.build(); |
베이스 리워드 지급 안내 UI 커스터마이징
...
사용자가 Feed 지면에 접근하면 일정 주기로 베이스 리워드를 지급합니다. 베이스 리워드 지급 시 보이는 UI를 수정할 수 있습니다. DefaultFeedFeedbackHandler의 상속 클래스는 작성합니다. 그리고, FeedConfig
의 feedFeedbackHandler에 작성한 클래스를 설정합니다알림 UI는 위의 이미지와 같습니다. 베이스 리워드 지급 알림 UI를 수정하여 좀 더 사용자 경험을 개선할 수 있습니다. 다음은 베이스 리워드 지급 알림 UI 를 수정하는 예시입니다.
Code Block | ||
---|---|---|
| ||
public class YourFeedFeedbackHandler extends DefaultFeedFeedbackHandler { @NotNull public View getBaseRewardNotificationView(@NotNull Context context, int reward) { // 베이스 리워드View 지급시view 피드 상단에 보여지는 notification view 입니다. } public void onBridgePointBaseRewardReceived(@NotNull Context context, int reward) {= LayoutInflater.from(context).inflate(R.layout.your_layout, null); // 베이스 리워드 지급시 브릿지 포인트 연동 중일 경우 호출되는 콜백입니다.return view } } |
Code Block | ||
---|---|---|
| ||
final FeedConfig feedConfig = new FeedConfig.Builder(context, "YOUR_FEED_UNIT_ID") .feedFeedbackHandler(YourFeedFeedbackHandler.class) .build(); |
...