ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

基于Android Tv制作一个Tv桌面(三)

2021-01-13 17:01:05  阅读:172  来源: 互联网

标签:桌面 name Tv app apps private int new Android


基于Android Tv制作一个Tv桌面(三)

接下来我们就开始分析一下代码部分,这里我就转载其他人写的吧,我一开始也是参考这篇文章的。
当然,我自己也添加了我自己在开发过程中写的代码和注释,对于新手来说没有这些注释还真的消耗头发

转载地址:https://blog.csdn.net/lzybilian/article/details/80001032

(AndroidManifest.xml)

<uses-permission android:name="android.permission.INTERNET" />   //这是申请网络的权限
<uses-permission android:name="android.permission.RECORD_AUDIO" />  //这是申请开发音频的权限

<uses-feature
    android:name="android.hardware.touchscreen"
    android:required="false" />           //因为电视一般不支持触屏,所以需要声明一下权限
<uses-feature
    android:name="android.software.leanback"
    android:required="true" />     //使用一些TV下面的控件时,需要的声明
<activity
    android:name=".MainActivity"
    android:banner="@drawable/app_icon_your_company"
    android:icon="@drawable/app_icon_your_company"
    android:label="@string/app_name"
    android:logo="@drawable/app_icon_your_company"
    android:screenOrientation="landscape">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        
        //因为我做的是桌面,所以加上了这两句
		<category android:name="android.intent.category.HOME" />	
        <category android:name="android.intent.category.DEFAULT" />
    	
    	//这个地方与手机端开发区别较大,这个主要是声明了这是一个TV项目,如果不加这个,那么运行在TV上时,是找不到这个应用的运行图标的
    	//但是我依然找不到图标哈哈,以后发现了问题所在再写下来吧
        <category android:name="android.intent.category.LEANBACK_LAUNCHER" />  
    </intent-filter>
</activity>

然后我就打开了MainActivity.xml,然后我发现里面竟然是空的。随后我就打开了MainActivity的资源文件。

<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main_browse_fragment"
    android:name="com.example.administrator.myfirst.MainFragment"  //这里是关键点,原来里面是引用了一个碎片。
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.administrator.myfirst.MainActivity"  
    tools:deviceIds="tv"
    tools:ignore="MergeRootFrame" />

然后就可以打开MainFragment.java。里面有四个方法,我们一一来分析一下。

//这些也写出来吧,不然看起来耗头发
 	private static final String TAG = "MainFragment";
    private static final int BACKGROUND_UPDATE_DELAY = 300;
    private static final int GRID_ITEM_WIDTH = 200;
    private static final int GRID_ITEM_HEIGHT = 200;

    private final Handler mHandler = new Handler();
    private Drawable mDefaultBackground;
    private DisplayMetrics mMetrics;
    private Timer mBackgroundTimer;
    private String mBackgroundUri;
    private BackgroundManager mBackgroundManager;

    private List<ResolveInfo> apps_list = MainActivity.apps;
    private List<String> sys_apps_name = MainActivity.system_app_name;
    private List<String> my_apps_name = MainActivity.my_app_name;
    private List<String> apps_name = MainActivity.name;
    private List<String> apps_pak = MainActivity.pak;
    private List<String> apps_cla = MainActivity.cla;
public void onActivityCreated(Bundle savedInstanceState) {
    Log.i(TAG, "onCreate");
    super.onActivityCreated(savedInstanceState);

    prepareBackgroundManager();

    setupUIElements();

    loadRows();

    setupEventListeners();
}

这里大家一看就明白这个方法的作用,初始化。

private void prepareBackgroundManager() {

    mBackgroundManager = BackgroundManager.getInstance(getActivity());
    mBackgroundManager.attach(getActivity().getWindow());

	//设置右边应用区域的背景颜色,被这个东西坑惨了ContextCompat.getColor(),看了下面的代码才反应过来
	//其实我也不知道它的原理是什么,参考百度吧
    mBackgroundManager.setColor(ContextCompat.getColor(getActivity(), R.color.search_opaque));

    mDefaultBackground = getResources().getDrawable(R.drawable.default_background);
    mMetrics = new DisplayMetrics();
    getActivity().getWindowManager().getDefaultDisplay().getMetrics(mMetrics);
}
private void setupUIElements() {
    // setBadgeDrawable(getActivity().getResources().getDrawable(
    // R.drawable.videos_by_google_banner));
    setTitle(getString(R.string.browse_title)); // Badge, when set, takes precedent
    // over title
    setHeadersState(HEADERS_ENABLED);
    setHeadersTransitionOnBackEnabled(false); //这里是设置左边引导的显示与否。

    // set fastLane (or headers) background color
    setBrandColor(getResources().getColor(R.color.background_gradient_start));  //设置左边引导的背景色
    // set search icon color
    setSearchAffordanceColor(getResources().getColor(R.color.search_opaque));
}

这个方法主要作用是产生页面数据

private void loadRows() {
    List<Movie> list = MovieList.setupMovies();  //Movie一个实现了序列化的Bean。setupMovies()是产生movie数据的方法

    mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());  //页面数据的适配器
    CardPresenter cardPresenter = new CardPresenter();         //这个比较重要下面贴上源码

   int sys_app_layer = 0;
   int my_app_layer = 0;
   if((sys_apps_name.size() % 8) == 0)
   {
   		sys_app_layer = (sys_apps_name.size() / 8);
   }
   else
   {
       sys_app_layer = (sys_apps_name.size() / 8) +1;
   }
	//(字怎么变黄了???)
   if((my_apps_name.size() % 8) == 0)
   {
       my_app_layer = (sys_apps_name.size() / 8);
   }
   else
   {
       my_app_layer = (sys_apps_name.size() / 8) +1;
   }
	//应领导要求,将app分成系统应用和第三方应用
   int i;
   HeaderItem header1 = new HeaderItem(0, MovieList.MOVIE_CATEGORY[0]);
   for (i = 0; i < sys_app_layer; i++) {
       ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
       for (int j = 0; j < 8 && ((8*i + j) < sys_apps_name.size()); j++) {
           //Log.d(TAG,"list.get["+(8*i+j)+"]:"+list.get(8*i + j));
           listRowAdapter.add(list.get(8*i + j));
       }
       if(i == 0)
       {
           rowsAdapter.add(new ListRow(header1, listRowAdapter));
       }
       else
       {
           rowsAdapter.add(new ListRow(listRowAdapter));
       }

   }

   HeaderItem header2 = new HeaderItem(i, MovieList.MOVIE_CATEGORY[1]);
   for (i = 0; i < my_app_layer; i++) {
       ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
       for (int j = 0; j < 8 && ((8*i + j) < my_apps_name.size()); j++) {
           //Log.d(TAG,"list.get["+(8*i+j)+"]:"+list.get(8*i + j));
           listRowAdapter.add(list.get(8*i + j + sys_apps_name.size()));
       }
       if(i == 0)
       {
           rowsAdapter.add(new ListRow(header2, listRowAdapter));
       }
       else
       {
           rowsAdapter.add(new ListRow(listRowAdapter));
       }

   }



 
  HeaderItem gridHeader = new HeaderItem(i, "PREFERENCES");   
 GridItemPresenter mGridPresenter = new GridItemPresenter();  
  ArrayObjectAdapter gridRowAdapter = new ArrayObjectAdapter(mGridPresenter); //里面传了一个Presenter 
gridRowAdapter.add(getResources().getString(R.string.grid_view));   
 gridRowAdapter.add(getString(R.string.error_fragment));   
 gridRowAdapter.add(getResources().getString(R.string.personal_settings));    
mRowsAdapter.add(new ListRow(gridHeader, gridRowAdapter));  //看了这个应该很清晰了   
 setAdapter(mRowsAdapter); //最后将mRowsAdapter设置}

主要就是实现了每个控件的绑定,设置数据

public class CardPresenter extends Presenter {
    private static final String TAG = "CardPresenter";

    private static final int CARD_WIDTH = 313;
    private static final int CARD_HEIGHT = 176;
    private static int sSelectedBackgroundColor;
    private static int sDefaultBackgroundColor;
    private Drawable mDefaultCardImage;

    private static void updateCardBackgroundColor(ImageCardView view, boolean selected) {
        int color = selected ? sSelectedBackgroundColor : sDefaultBackgroundColor;
        // Both background colors should be set because the view's background is temporarily visible
        // during animations.
        view.setBackgroundColor(color);
        view.findViewById(R.id.info_field).setBackgroundColor(color);
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent) {
        Log.d(TAG, "onCreateViewHolder");

        sDefaultBackgroundColor = parent.getResources().getColor(R.color.default_background);
        sSelectedBackgroundColor = parent.getResources().getColor(R.color.selected_background);
        /*
         * This template uses a default image in res/drawable, but the general case for Android TV
         * will require your resources in xhdpi. For more information, see
         * https://developer.android.com/training/tv/start/layouts.html#density-resources
         */

		//下面这个mDefaultCardImage我将它移到了onBindViewHolder方法里面
        //mDefaultCardImage = parent.getResources().getDrawable(R.drawable.movie);

        ImageCardView cardView = new ImageCardView(parent.getContext()) {
            @Override
            public void setSelected(boolean selected) {
                updateCardBackgroundColor(this, selected);  //这句很关键,它实现了当选择改变的时候,选中效果的出现
                super.setSelected(selected);
            }
        };
        cardView.setFocusable(true);
        cardView.setFocusableInTouchMode(true);
        updateCardBackgroundColor(cardView, false);
        return new ViewHolder(cardView);
    }

    @Override
    public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
        Movie movie = (Movie) item;


		//这里是根据item的Title与列表apps_name做对比,目的是获得i,获得准确的apps_icon
		//至于为什么这样做,我会在文章后面画个图解释
		for(int i=0; i<apps_name.size(); i++)
        {
            if(((Movie) item).getTitle() == apps_name.get(i))
            {
                mDefaultCardImage = apps_icon.get(i);
            }
        }


        ImageCardView cardView = (ImageCardView) viewHolder.view;

        Log.d(TAG, "onBindViewHolder");
        if (movie.getCardImageUrl() != null) {
            cardView.setTitleText(movie.getTitle());
            //cardView.setContentText(movie.getStudio());

			//这里是设置layout与父组件边框的距离,我没有找到调节父组件之间的距离的方法
			//领导又觉得它们挤着慌,只好改一下这里了
			FrameLayout.LayoutParams layout = new FrameLayout.LayoutParams(
            FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
            layout.setMargins(30, 15, 30, 15);


			//设置图标与父控件的距离,这里可以调节图标大小和形状
			//说到这不得不承认我真的是菜,我没有找到将图标设置成原图的方法,只能这样把它硬挤成型
            ImageView imageView = cardView.getMainImageView();
            imageView.setPadding(75, 25, 75, 25);
            imageView.setScaleType(ImageView.ScaleType.FIT_XY);


            cardView.setMainImageDimensions(CARD_WIDTH, CARD_HEIGHT);
            Glide.with(viewHolder.view.getContext())
                    .load(movie.getCardImageUrl())
                    .centerCrop()
                    .error(mDefaultCardImage)
                    .into(layout);
        }
    }

    @Override
    public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {
        Log.d(TAG, "onUnbindViewHolder");
        ImageCardView cardView = (ImageCardView) viewHolder.view;
        // Remove references to images so that the garbage collector can free up memory
        cardView.setBadgeImage(null);
        cardView.setMainImage(null);
    }
}

这个方法设置了监听

private void setupEventListeners() {
    setOnSearchClickedListener(new View.OnClickListener() {

		
        @Override
        public void onClick(View view) {
        	//左上角搜索点击事件
            Toast.makeText(getActivity(), "Implement your own in-app search", Toast.LENGTH_LONG)
                    .show();
        }
    });
	
	//item的监听
    setOnItemViewClickedListener(new ItemViewClickedListener());
    setOnItemViewSelectedListener(new ItemViewSelectedListener());
}

解释一下之前的那个循环吧,下面图中的大黑框是屏幕,黑框外面的小框则是超出屏幕外面的图标,图标下面都有app的名字我这里是把app的各种信息分别存在不同的列表中,位置也是对应好的;但是一打开应用我就傻眼了,app名字和图标对应不上,原因就在于它加载图标时先把屏幕内的填上,再搞屏幕外面的。所以我就只能根据app名字去找到对应的图标,再将它加载进去,这样就不会乱了
在这里插入图片描述

标签:桌面,name,Tv,app,apps,private,int,new,Android
来源: https://blog.csdn.net/weixin_48856816/article/details/112563441

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有