基于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-featureandroid:name="android.hardware.touchscreen"android:required="false" />           //因为电视一般不支持触屏,所以需要声明一下权限
<uses-featureandroid:name="android.software.leanback"android:required="true" />     //使用一些TV下面的控件时,需要的声明
<activityandroid: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 titlesetHeadersState(HEADERS_ENABLED);setHeadersTransitionOnBackEnabled(false); //这里是设置左边引导的显示与否。// set fastLane (or headers) background colorsetBrandColor(getResources().getColor(R.color.background_gradient_start));  //设置左边引导的背景色// set search icon colorsetSearchAffordanceColor(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);}@Overridepublic 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()) {@Overridepublic void setSelected(boolean selected) {updateCardBackgroundColor(this, selected);  //这句很关键,它实现了当选择改变的时候,选中效果的出现super.setSelected(selected);}};cardView.setFocusable(true);cardView.setFocusableInTouchMode(true);updateCardBackgroundColor(cardView, false);return new ViewHolder(cardView);}@Overridepublic 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);}}@Overridepublic 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 memorycardView.setBadgeImage(null);cardView.setMainImage(null);}
}

这个方法设置了监听

private void setupEventListeners() {setOnSearchClickedListener(new View.OnClickListener() {@Overridepublic 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名字去找到对应的图标,再将它加载进去,这样就不会乱了

基于Android Tv制作一个Tv桌面(三)相关推荐

  1. 基于Android Tv制作一个Tv桌面(二)

    标题基于Android Tv制作一个Tv桌面(二) 这里是获取APP的各种信息,不知道为什么这一步只能在主类MainActivity 上进行,不能在其他的类进行此操作,也许是我见识短浅的原因吧,因为其 ...

  2. 基于C#制作一个ChatGPT桌面助手

    基于C#制作一个ChatGPT桌面助手,在工作或者学习时提升自己的效率,工欲善其事,必先利其器. 一.前言 1.1.什么是ChatGPT 1.2.ChatGPT官网及key申请 二.后台项目 2.1. ...

  3. 物联网控制APP入门专题(四)---使用android studio制作一个控制页面的APP框架

    摘要:上篇文章讲了如何用阿里云IoT Studio快速制作一个网页版的手机端,以及通过第三方平台将这个网页打包成一个APK文件,使它可以安装到手机实现APP的功能.但是使用第三方平台做的APP是需要收 ...

  4. 怎么用Android做登录界面,利用Android怎么制作一个APP登录界面

    利用Android怎么制作一个APP登录界面 发布时间:2020-12-02 17:09:10 来源:亿速云 阅读:79 作者:Leah 这期内容当中小编将会给大家带来有关利用Android怎么制作一 ...

  5. 如何使用android studio制作一个阿里云物联网APP

    摘要:要想学会物联网技术,需要掌握的知识真的有太多了,其中一个关键的技能,也是决定物联网技能等级的,就是移动端开发能力.当然,现在有很多平台都提供了各种各样的移动端应用,但是都相对封闭,我们无法掌握其 ...

  6. 蓝牙App设计2:使用Android Studio制作一个蓝牙软件(包含:代码实现等)

    前言:蓝牙聊天App设计全部有三篇文章(一.UI界面设计,二.蓝牙搜索配对连接实现,三.蓝牙连接聊天),这篇文章是:二.蓝牙搜索配对连接实现. 课程1:Android Studio小白安装教程,以及第 ...

  7. 微信小程序|基于小程序制作一个超酷的个人简历

    你还在用以前的方式投简历吗?趁着金三银四来临之际,跟随此文使用小程序制作一个便携超酷的个人简历,高调炫技,愉快的收offer吧! 一.小程序 <

  8. 基于小程序制作一个ChatGPT聊天机器人

    在AI技术日新月异的浪潮中,将ChatGPT与实战开发相结合,制作一个随身携带的聊天机器人,紧贴前沿的同时稳固基础. 一.前言 1.1.什么是ChatGPT 1.2.什么是文本完成 二.API 2.1 ...

  9. android菜单动画,利用 android studio 制作一个菜单动画

    目的:利用Android studio 编一个菜单动画,以便初步了解Android studio的基本操作,初步了解Android开发的思考方法. 技术: 1.RelativeLayout. 2.sr ...

  10. 基于小程序制作一个猜拳小游戏

    在工作学习之余玩一会游戏既能带来快乐,还能缓解生活压力,跟随此文一起制作一个小程序游戏吧. 创建小程序 功能实现 界面优化 代码块 创建小程序 访问微信公众平台,点击账号注册. 选择小程序,并在表单填 ...

最新文章

  1. dns网络服务的搭建和配置
  2. Linux下select, poll和epoll IO模型的详解
  3. C#入门教程-注释的使用
  4. 【Cannot convert from [[B] to】 @RabbitListener 反序列化报错
  5. Eclipse里做JBPM工作流gpd.xml中文乱码问题解决(包括控制台乱码解决)
  6. 数据丢失引起宕机怎么办?
  7. ue4cmd怎么调用_虚幻引擎UE4-命令行使用的一些详细技巧
  8. K8s 原理架构介绍(一)
  9. 中断占据CPU时间的计算问题
  10. 阿里 java ide_纯JAVA版JAVA IDE环境(源码)
  11. java代码行数_Java统计代码行数
  12. 【洛谷试炼场】洛谷新手村——洛谷的第一个任务
  13. 微生物组-扩增子16S分析和可视化(2022.7本周开课)
  14. 图片传输到ipfs节点然后将生成的ipfs访问链接存到区块链
  15. 2017-2018 ACM-ICPC, Asia Daejeon Regional Contest:Gym 101667B
  16. 九年级计算机课程教案,九年级信息技术 5.2.3《计算机网络》教案
  17. 如何自动生成参考文献格式
  18. 侵犯计算机软件著作权的行为,侵犯计算机软件著作权的行为有哪些?
  19. 最大熵模型怎么理解?熵是什么??
  20. nginx的负载均衡模块详解

热门文章

  1. 《Python安全攻防:渗透测试实战指南》学习一
  2. python中shuffle是什么意思_python中shuffle()方法的功能详解
  3. “海青杯”复赛群雄逐鹿,凡科为青年创业翱翔插上翅膀
  4. FPGA:ov7725摄像头通过VGA/HDMI显示RGB565格式的图像
  5. Unity UGUI 图文混排
  6. 下载并安装Pandoc
  7. 留得些许清影,幽香直到人间
  8. python监听鼠标键盘_python用pynput监听控制键盘鼠标
  9. uniapp微信登录
  10. 【pyqt5学习】—— 滑动条Qslider、计数器QSpinBox学习