欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

AndroidTV开发7————实现仿小米电视和各种盒子TV焦点放大缩小效果

程序员文章站 2022-04-15 18:04:25
AndroidTV中最常见的就是焦点效果,这个实现很简单,在代码设置view.setFocusable(true),布局中focusable="true",然后添加view获得焦点时的效果即可。但是本文不讲这些,而是讲解View获取焦点有一个放大缩小效果,当view放大时处于临近的View之上并且不能被遮挡,当view缩小时要恢复原来的大小。1.先放几张效果图:2.方案分析,网上的有如下方案:(1):MainUpView:(2):MetroItemFrameLayout(何俊林大神的...

AndroidTV中最常见的就是焦点效果,这个实现很简单,在代码设置view.setFocusable(true),布局中focusable="true",然后添加view获得焦点时的效果即可。但是本文不讲这些,而是讲解View获取焦点有一个放大缩小效果,当view放大时处于临近的View之上并且不能被遮挡,当view缩小时要恢复原来的大小。

1.先放几张效果图:

AndroidTV开发7————实现仿小米电视和各种盒子TV焦点放大缩小效果

AndroidTV开发7————实现仿小米电视和各种盒子TV焦点放大缩小效果

2.方案分析,网上的方案和资料如下:

(1):MainUpView:

(2):MetroItemFrameLayout(何俊林大神的方案):博客地址:https://blog.csdn.net/hejjunlin/article/details/52792562

(3)Android tv metro,项目地址:https://gitee.com/kumei/android_tv_metro

(4)Android tv frame,项目地址:https://gitee.com/kumei/android-tv-frame-new

(5)TvRecyclerView,项目地址:https://github.com/henryblue/TvRecyclerView

(6)TvRecyclerView,项目地址:https://github.com/zhousuqiang/TvRecyclerView

(7)TVRecyclerView,项目地址:https://github.com/Fredlxy/TVRecyclerView

(8)Android tv frame,项目地址:https://github.com/songwenju/CustomTvRecyclerView

(9)TvWidget,项目地址:https://github.com/evilbinary/TvWidget

(10)BorderViewDemo,项目地址:https://github.com/lf8289/BorderViewDemo

(11)TvFocusBorder,项目地址:https://github.com/zhousuqiang/TvFocusBorder

(12) Android Tv Widget Demo,项目地址: https://github.com/zhousuqiang/TvWidget

(13)SMTVLauncher,项目地址:https://github.com/FrozenFreeFall/SMTVLauncher

(14)AndroidTVLauncher,项目地址:https://github.com/JackyAndroid/AndroidTVLauncher

(15)TVSample,项目地址:https://github.com/hejunlin2013/TVSample

(16)Leanback桌面demo,项目地址:https://gitee.com/chuangshiji/Launcher

3.以上方案尝试了一半,由于时间和项目周期问题,所以有些没来得及尝试,而且接入成本有点大,每个项目都不一样,选择适合自己的才最重要,我们不要拘泥于某一种方案或者第三方库.这里我根据以上方案总结出一份属于我自己的方案,主要代码如下:

 

AndroidTV开发7————实现仿小米电视和各种盒子TV焦点放大缩小效果

AndroidTV开发7————实现仿小米电视和各种盒子TV焦点放大缩小效果

4.Fragment完整代码如下:

package com.example.tvrecyclerview.fragment;

import android.os.Build;
import android.view.View;
import android.widget.ImageView;

import com.example.tvrecyclerview.R;

/**
 * @author: njb
 * @date: 2020/9/24 0024 0:47
 * @desc:
 */
public class OtherFragment extends FragmentBase implements View.OnFocusChangeListener {
    private static final float scale0 = 1f;
    private static final float scaleL = 1.12f;
    private static final float scaleS = 1.22f;
    private static final float z1 = 0f;
    private static final float z2 = 10f;
    private static final long animateDuration = 20;
    private static View lastFocus;
    private ImageView ivRecentControl, ivCollectControl, ivRemoteControl, ivHandleControl, ivQrCodeControl;

    @Override
    protected int getLayoutRes() {
        return R.layout.fragment_other;
    }

    @Override
    protected void rootViewNoNull() {
        super.rootViewNoNull();
        if(null != lastFocus){
            lastFocus.requestFocus();
        }
    }

    @Override
    protected void initView(View rootView) {
        super.initView(rootView);
        //初始化控件
        ivRecentControl = rootView.findViewById(R.id.iv_my_recent);
        ivCollectControl = rootView.findViewById(R.id.iv_my_collect);
        ivHandleControl = rootView.findViewById(R.id.iv_my_handle);
        ivRemoteControl = rootView.findViewById(R.id.iv_my_remote);
        ivQrCodeControl = rootView.findViewById(R.id.iv_my_qrcode);
        //初始化焦点事件
        ivRecentControl.setOnFocusChangeListener(this);
        ivCollectControl.setOnFocusChangeListener(this);
        ivRemoteControl.setOnFocusChangeListener(this);
        ivHandleControl.setOnFocusChangeListener(this);
        ivQrCodeControl.setOnFocusChangeListener(this);
    }

    @Override
    public void onFocusChange(final View v, boolean hasFocus) {
        //初始化放大倍数
        float scaleX1, scaleX2, scaleY1, scaleY2;
        scaleX1 = scaleY1 = scaleX2 = scaleY2 = scale0;
        //给获取焦点的view设置倍数
        if (v.getId() == R.id.iv_my_recent || v.getId() == R.id.iv_my_collect) {
            scaleX2 = scaleY2 = scaleL;
        }
        if (v.getId() == R.id.iv_my_handle || v.getId() == R.id.iv_my_remote || v.getId() == R.id.iv_my_qrcode) {
            scaleX2 = scaleY2 = scaleS;
        }
        //获得焦点时的状态和倍数
        if (hasFocus) {
            lastFocus = v;
            //在android5.0以上的效果
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                v.animate()
                        .scaleXBy(scaleX1)
                        .scaleX(scaleX2)
                        .scaleYBy(scaleY1)
                        .scaleY(scaleY2)
                        .zBy(z1)
                        .z(z2)
                        .setDuration(animateDuration);
            } else {
                //在android5.0以下的效果
                v.animate()
                        .scaleXBy(scaleX1)
                        .scaleX(scaleX2)
                        .scaleYBy(scaleY1)
                        .scaleY(scaleY2)
                        .withEndAction(new Runnable() {
                            @Override
                            public void run() {
                                //防止view被遮挡
                                v.bringToFront();
                            }
                        })
                        .setDuration(animateDuration);
            }
        } else {
            //view在焦点消失后的倍数和状态
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                v.animate()
                        .scaleXBy(scaleX2)
                        .scaleX(scaleX1)
                        .scaleYBy(scaleY2)
                        .scaleY(scaleY1)
                        .zBy(z2)
                        .z(z1)
                        .setDuration(animateDuration);
            } else {
                v.animate()
                        .scaleXBy(scaleX2)
                        .scaleX(scaleX1)
                        .scaleYBy(scaleY2)
                        .scaleY(scaleY1)
                        .setDuration(animateDuration);
            }
        }
    }
}

5.布局文件fragment_other.xml代码:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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="match_parent"
    android:background="@color/color_blue">

   <include
       layout="@layout/layout_more_game"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       app:layout_constraintBottom_toBottomOf="parent"
       app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

6.layout_more_game.xml代码:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:id="@+id/cl_more"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="20dp"
    android:layout_marginTop="16dp"
    android:clipChildren="false"
    android:clipToPadding="false"
    tools:ignore="MissingConstraints">


    <ImageView
        android:id="@+id/iv_my_recent"
        android:layout_width="91dp"
        android:layout_height="111dp"
        android:background="@drawable/bg_more_focus"
        android:focusable="true"
        android:padding="2dp"
        android:scaleType="fitXY"
        android:clipChildren="false"
        android:clipToPadding="false"
        android:src="@mipmap/ic_recent"
        android:layout_marginEnd="16dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/iv_my_collect"/>


    <ImageView
        android:id="@+id/iv_my_collect"
        android:layout_width="91dp"
        android:layout_height="111dp"
        android:layout_marginEnd="16dp"
        android:background="@drawable/bg_more_focus"
        android:focusable="true"
        android:padding="2dp"
        android:scaleType="fitXY"
        android:clipChildren="false"
        android:clipToPadding="false"
        android:src="@mipmap/ic_collect"
        app:layout_constraintLeft_toRightOf="@+id/iv_my_recent"
        app:layout_constraintRight_toLeftOf="@id/iv_my_handle"/>

    <ImageView
        android:id="@+id/iv_my_handle"
        android:layout_width="0dp"
        android:layout_height="111dp"
        android:layout_marginEnd="16dp"
        android:background="@drawable/bg_more_focus"
        android:focusable="true"
        android:padding="2dp"
        android:scaleType="fitXY"
        android:clipChildren="false"
        android:clipToPadding="false"
        android:src="@mipmap/ic_handle_game"
        app:layout_constraintLeft_toRightOf="@+id/iv_my_collect"
        app:layout_constraintRight_toLeftOf="@+id/iv_my_remote"/>


    <ImageView
        android:id="@+id/iv_my_remote"
        android:layout_width="0dp"
        android:layout_height="111dp"
        android:background="@drawable/bg_more_focus"
        android:focusable="true"
        android:padding="2dp"
        android:scaleType="fitXY"
        android:layout_marginEnd="16dp"
        android:clipChildren="false"
        android:clipToPadding="false"
        android:src="@mipmap/ic_remote_control"
        app:layout_constraintLeft_toRightOf="@+id/iv_my_handle"
        app:layout_constraintRight_toLeftOf="@+id/iv_my_qrcode"/>

    <ImageView
        android:id="@+id/iv_my_qrcode"
        android:layout_width="0dp"
        android:layout_height="111dp"
        android:background="@drawable/bg_more_focus"
        android:focusable="true"
        android:padding="2dp"
        android:scaleType="fitXY"
        android:clipChildren="false"
        android:clipToPadding="false"
        android:src="@mipmap/ic_qrcode_control"
        app:layout_constraintLeft_toRightOf="@+id/iv_my_remote"
        app:layout_constraintRight_toRightOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

7.实现的效果图如下:

AndroidTV开发7————实现仿小米电视和各种盒子TV焦点放大缩小效果

8.简单分析:要想 实现以上效果需要考虑几个问题:

a.放大后的倍数

b.缩小后的倍数

c.view处于临界view之上的边界被切问题

d.在android5.0以上和5.0以下的适配问题

e.封装成一个工具类,因为现在的界面基本上都很复杂,如果是多个布局需要写多个view和倍数等,这样的话每个界面都要写很多次,感觉都是做重复的工作。

9.以上就是TV盒子上的焦点效果实现过程和原理简单分析,后面会出一篇博客详细分析怎么计算倍数,下一篇将会分析怎么封装成一个工具类和封装遇到的问题,欢迎小伙伴们前来讨论留言,有错误指正出来,我会及时更改。

项目的源码地址如下:https://gitee.com/jackning_admin/TvRecyclerView

本文地址:https://blog.csdn.net/u012556114/article/details/108860875

相关标签: AndroidTV开发