2. Android high imitation NetEase cloud music - guide interface and advertising interface implementation

renderings

art_ad_guide.png

The renderings are image advertisements, video advertisements, and guide interfaces in sequence.

Series Article Directory Navigation

Table of contents

1. Implementation Analysis

The advertising interface is to display pictures and videos, so you can put a picture control, video control, skip button, prompt button, and WiFi preload prompt are all placed in the top container.

2. Advertising interface layout

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".component.ad.activity.AdActivity">
    <!--图片广告-->
    <ImageView
        android:id="@+id/image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop" />

    <!--视频播放器
    VideoView默认没法设置视频填充整个控件,所以不用他-->
    <com.tencent.rtmp.ui.TXCloudVideoView
        android:id="@+id/video"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="gone" />
    <!--/播放器-->

    <!--广告控制层-->
    <RelativeLayout
        android:id="@+id/ad_control"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/preload"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="@dimen/padding_meddle"
            android:layout_marginTop="@dimen/d50"
            android:layout_marginBottom="@dimen/d50"
            android:background="@drawable/shape_button_transparent_radius_small"
            android:gravity="center"
            android:padding="@dimen/d5"
            android:text="@string/wifi_preload"
            android:textColor="?attr/colorLightWhite"
            android:textSize="@dimen/text_small"
            android:visibility="gone" />

        <!--跳过广告按钮-->
        <TextView
            android:id="@+id/skip"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_marginTop="@dimen/d50"
            android:layout_marginRight="@dimen/padding_large"
            android:layout_marginBottom="@dimen/d50"
            android:background="@drawable/shape_button_transparent_radius_small"
            android:gravity="center"
            android:padding="@dimen/padding_meddle"
            android:textColor="?attr/colorLightWhite"
            android:textSize="@dimen/text_meddle"
            app:cornerRadius="@dimen/d30"
            tools:text="@string/skip_ad_count" />
            <!--打开广告按钮-->
            <TextView
                android:id="@+id/primary"
                android:layout_width="match_parent"
                android:layout_height="@dimen/d60"
                android:background="@drawable/shape_button_transparent_radius_large"
                android:gravity="center"
                android:text="@string/ad_click_tip"
                android:textColor="?attr/colorLightWhite"
                android:textSize="@dimen/text_large"
                app:cornerRadius="@dimen/d30" />
        </com.facebook.shimmer.ShimmerFrameLayout>
    </RelativeLayout>
</RelativeLayout>

3. Display Ads

The advertising data is cached locally on the home page in advance, and the purpose is to display it locally faster, because the advertising interface is only a few seconds, and it is a waste of time to go to the network to request data.

@Override
protected void initDatum() {
    super.initDatum();

    //获取广告信息
    data = sp.getSplashAd();
    if (data == null) {
        next();
        return;
    }

    //显示广告信息
    show();
}

private void show() {
    File targetFile = FileUtil.adFile(getHostActivity(), data.getIcon());
    if (!targetFile.exists()) {
        //记录日志,因为正常来说,只要保存了,文件不能丢失
        next();
        return;
    }

    SuperViewUtil.show(binding.adControl);

    switch (data.getStyle()) {
        case Constant.VALUE0:
            showImageAd(targetFile);
            break;
        case Constant.VALUE10:
            showVideoAd(targetFile);
            break;
    }
}

/**
 * 显示视频广告
 *
 * @param data
 */
private void showVideoAd(File data) {
    SuperViewUtil.show(binding.video);
    SuperViewUtil.show(binding.preload);

    //在要用到的时候在初始化,更节省资源,当然播放器控件也可以在这里动态创建
    //设置播放监听器

    //创建 player 对象
    player = new TXVodPlayer(getHostActivity());

    //静音,当然也可以在界面上添加静音切换按钮
    player.setMute(true);

    //关键 player 对象与界面 view
    player.setPlayerView(binding.video);

    //设置播放监听器
    player.setVodListener(this);

    //铺满
    binding.video.setRenderMode(TXLiveConstants.RENDER_MODE_FULL_FILL_SCREEN);

    //开启硬件加速
    player.enableHardwareDecode(true);

    player.startPlay(data.getAbsolutePath());
}

/**
 * 显示图片广告
 *
 * @param data
 */
private void showImageAd(File data) {
    ImageUtil.showLocalImage(getHostActivity(), binding.image, data.getAbsolutePath());

    startCountDown(5000);
}

skip ads

To skip an ad is to cancel the countdown and go directly to the next interface.

//跳过广告按钮
binding.skip.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        //取消倒计时
        cancelCountDown();

        next();
    }
});

click ad

Clicking on the advertisement is to cancel the countdown, enter the main interface, and then display the advertisement interface.

Bootstrap interface layout

//点击广告按钮
binding.primary.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        //取消倒计时
        cancelCountDown();

        action = Constant.ACTION_AD;

        next();
    }
});

Boot interface logic

Scroll the ViewPager container left and right at the top, you can also use ViewPager2, the middle is the indicator, and the bottom is the button.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:ixuea="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!--左右滚动控件-->
    <androidx.viewpager.widget.ViewPager
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

    ...

    <!--按钮容器-->
    <LinearLayout
        android:layout_marginBottom="@dimen/d30"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <!--占位控件-->
        <View
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_weight="1" />

        <!--登录注册按钮-->
        <com.google.android.material.button.MaterialButton
            android:id="@+id/login_or_register"
            style="@style/SuperButton.Primary"
            android:layout_width="wrap_content"
            android:minWidth="@dimen/d130"
            android:text="@string/login_or_register" />

        <include layout="@layout/fill" />

        <!--立即体验按钮-->
        <com.google.android.material.button.MaterialButton
            android:id="@+id/experience_now"
            style="@style/Widget.MaterialComponents.Button.UnelevatedButton"
            android:layout_width="wrap_content"
            android:layout_height="@dimen/d55"
            android:layout_centerVertical="true"
            android:layout_marginHorizontal="@dimen/d5"
            android:layout_toRightOf="@+id/select_image"
            android:backgroundTint="?attr/colorLightWhite"
            android:minWidth="@dimen/button_width_large"
            android:text="@string/experience_now"
            android:textColor="@color/black80"
            android:textSize="@dimen/text_small"
            ixuea:strokeColor="?attr/colorPrimary"
            ixuea:strokeWidth="@dimen/d1" />

        <include layout="@layout/fill" />
    </LinearLayout>
</LinearLayout>

Download ads

Whether it is a picture or a video, it is in the file mode. Of course, before downloading, it is necessary to judge whether it is WiFi, and download it if it is not downloaded.

private void downloadAd(Ad data) {
    if (SuperNetworkUtil.isWifiConnected(getHostActivity())) {
        sp.setSplashAd(data);

        //判断文件是否存在,如果存在就不下载
        File targetFile = FileUtil.adFile(getHostActivity(), data.getIcon());
        if (targetFile.exists()) {
            return;
        }

        new Thread(
                new Runnable() {
                    @Override
                    public void run() {

                        try {
                            //FutureTarget会阻塞
                            //所以需要在子线程调用
                            FutureTarget<File> target = Glide.with(getHostActivity().getApplicationContext())
                                    .asFile()
                                    .load(ResourceUtil.resourceUri(data.getIcon()))
                                    .submit();

                            //获取下载的文件
                            File file = target.get();

                            //将文件拷贝到我们需要的位置
                            FileUtils.moveFile(file, targetFile);

                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
        ).start();
    }
}

Summarize

No matter which interface it is, it is not difficult, but as we said, writing code is like art, and it is quite troublesome to write the details, such as: whether to download advertisements should be downloaded when the network is idle, so as to avoid affecting normal network requests, At the same time, after downloading, it is necessary to add a certain mechanism to prevent easy skipping of advertisements, etc.; if you want to generate income, large companies have their own advertising platforms, and it is more convenient for small and medium-sized projects to use the aggregation SDK.

Guess you like

Origin juejin.im/post/7121989624376868877