Android TV 开发 (1)
本文来自网易云社区
作者:孙有军
前言
这里主要记录几个TV问题的解决方案,如果对这个不感兴趣的其实就不用往下看了。
这几天有一个需求就是要求出一个TV版本的app,之前没有具体的了解Tv版的app有手机端的app到底有什么区别,因此就做了一下研究,写了些Demo,在做的过程中确实出现了好几个问题。一开始碰到这些问题时,浅尝辄止的试了试,发现很多都没有解决方案,本着外事问google的,search了一把,也没有结果,可能是TV做的人比较少,网上搜出来的都是照着谷歌官方的样例实现了一把而已,因此就仔细的研究了一下这些问题,这里把解决这些问题的方案描述出来,希望其他人能少走弯路,如果有更好的解决方案也希望大家探讨分享。
开发过程
虽然google官方写的是手机app不用做太多改动就可以运行在Tv上,但是终究两种还是有部分区别的,这里还是要针对TV版做部分设置。
首先是配置文件的改动,需要在AndroidManifest中配置如下属性:
<uses-feature
android:name="android.hardware.touchscreen"
android:required="false"/>
<uses-feature
android:name="android.software.leanback"
android:required="true"/>
同时还需要配置一个action为android.intent.action.MAIN,category为android.intent.category.LEANBACK_LAUNCHER的Activity,类似如下:
<activity
android:name="im.yixin.home.HomeActivity"
android:label="@string/app_name"
android:screenOrientation="landscape">
<intent-filter>
<action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
</intent-filter>
</activity>
如果记不住上面需要配置的内容其实也没有关系,可以新创建一个TV工程,默认创建的TV工程就已经包含了上述的配置,并且该工程就相当于一个demo了,是可以直接运行的一个工程,里面包含了Tv开发的很多控件,如果你要学习这也是很好的学习资料了,其实后续的内容也是根据这里的内容进行参照学习的。
这里附带一句,Android的sdk中的samples中的tv样例程序直接导入是运行不起来的,需要修改很多东西,但是实质内容与新创建的工程没有什么区别,因此也可以不用导入样例程序进行学习了。
根据前面的样例图,主界面配置页面如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/global_bg"
android:orientation="vertical"
android:paddingLeft="42dp"
android:paddingRight="42dp"> <RelativeLayout
android:layout_width="match_parent"
android:layout_height="@dimen/gap_86_dp"
android:clickable="true"> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:drawableLeft="@drawable/tv_logo"
android:drawablePadding="@dimen/gap_8_dp"
android:gravity="center"
android:text="@string/itv_name"
android:textColor="@color/white"
android:textSize="@dimen/text_size_20"/> <TextView
android:id="@+id/settings_tab"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:layout_marginRight="@dimen/gap_45_dp"
android:background="@drawable/navigation_tab_bar_selector"
android:focusable="true"
android:gravity="center"
android:text="@string/setting"
android:textColor="@color/navigation_text_selector"
android:textSize="@dimen/text_size_20"/> <TextView
android:id="@+id/contact_tab"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginRight="@dimen/gap_45_dp"
android:layout_toLeftOf="@id/settings_tab"
android:background="@drawable/navigation_tab_bar_selector"
android:focusable="true"
android:gravity="center"
android:text="@string/contact"
android:textColor="@color/navigation_text_selector"
android:textSize="@dimen/text_size_20"/> <TextView
android:id="@+id/dial_tab"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginRight="@dimen/gap_65_dp"
android:layout_toLeftOf="@id/contact_tab"
android:background="@drawable/navigation_tab_bar_selector"
android:focusable="true"
android:gravity="center"
android:text="@string/dial"
android:textColor="@color/navigation_text_selector"
android:textSize="@dimen/text_size_20"/>
</RelativeLayout> <View
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_marginBottom="@dimen/gap_50_dp"
android:background="@color/gray1"/> <FrameLayout
android:id="@+id/tab_container"
android:layout_width="match_parent"
android:layout_height="match_parent"></FrameLayout>
</LinearLayout>
界面的代码如下:
public class HomeActivity extends Activity implements View.OnClickListener {
public static void start(Context context) {
Intent intent = new Intent(context, HomeActivity.class);
context.startActivity(intent);
}
private static final String[] TAGS = {"dial", "contact", "my"};
private FragmentManager manager;
private int showTabIndex = -1;
private TextView dialTab;
private TextView contactTab;
private TextView myTab;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
findViews();
setViewsListener();
init();
selectTab(0);
}
private void findViews() {
dialTab = (TextView) findViewById(R.id.dial_tab);
contactTab = (TextView) findViewById(R.id.contact_tab);
myTab = (TextView) findViewById(R.id.settings_tab);
}
private void setViewsListener() {
dialTab.setOnClickListener(this);
contactTab.setOnClickListener(this);
myTab.setOnClickListener(this);
}
private void init() {
manager = getFragmentManager();
}
private void selectTab(int index) {
if (index == showTabIndex) {
return;
}
dialTab.setSelected(index == 0);
contactTab.setSelected(index == 1);
myTab.setSelected(index == 2);
FragmentTransaction transaction = manager.beginTransaction();
hideFragment(showTabIndex, transaction);
showTabIndex = index;
showFragment(showTabIndex, transaction);
transaction.commit();
}
private void hideFragment(int tabIndex, FragmentTransaction transaction) {
Fragment fragment = getFragmentByIndex(tabIndex);
if (fragment != null) {
transaction.hide(fragment);
}
}
private Fragment getFragmentByIndex(int index) {
if (index >= 0 && index < TAGS.length) {
return manager.findFragmentByTag(TAGS[index]);
}
return null;
}
private void showFragment(int tabIndex, FragmentTransaction transaction) {
Fragment fragment = getFragmentByIndex(tabIndex);
if (fragment == null) {
switch (tabIndex) {
case 0:
fragment = new DialFragment();
break;
case 1:
/* fragment = new ContactFragment();*/
fragment = new VerticalGridFragment();
break;
case 2:
fragment = new MyFragment();
break;
}
transaction.add(R.id.tab_container, fragment, TAGS[tabIndex]);
//transaction.addToBackStack(TAGS[tabIndex]);
} else {
transaction.show(fragment);
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.dial_tab:
selectTab(0);
return;
case R.id.contact_tab:
selectTab(1);
return;
case R.id.settings_tab:
selectTab(2);
// VerticalGridActivity.start(this);
return;
}
}
}
该界面主要采用Fragment来实现三个界面,分别为拨号页面,好友,设置界面,其中拨号界面又包含两个子的Fragment,我们来继续看看拨号界面与好友界面,设置界面是一个充数的界面啥都没有做。
网易云免费体验馆,0成本体验20+款云产品!
更多网易研发、产品、运营经验分享请访问网易云社区
相关文章:
【推荐】 基于Docker的UI自动化初探
【推荐】 深入解析SQLServer高可用镜像实现原理
【推荐】 Android输入法弹出时覆盖输入框问题
Android TV 开发 (1)的更多相关文章
- Android TV开发总结(六)构建一个TV app的直播节目实例
请尊重分享成果,转载请注明出处:http://blog.csdn.net/hejjunlin/article/details/52966319 近年来,Android TV的迅速发展,传统的有线电视受 ...
- Android TV开发总结(五)TV上屏幕适配总结
前言:前面几篇总结一些TV上的小Sample,开源到GitHub:https://github.com/hejunlin2013/TVSample, 点击链接,可以持续关注.今天总结下TV上屏幕适配. ...
- Android TV开发总结(三)构建一个TV app的焦点控制及遇到的坑
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52835829 前言:上篇中,&l ...
- 聊聊真实的 Android TV 开发技术栈
智能电视越来越普及了,华为说四月发布智能电视跳票了,一加也说今后要布局智能电视,在智能电视方向,小米已经算是先驱了.但是还有不少开发把智能电视简单的理解成手机屏幕的放大,其实这两者并不一样. 一.序 ...
- Android TV开发总结(七)构建一个TV app中的剧集列表控件
原文:Android TV开发总结(七)构建一个TV app中的剧集列表控件 版权声明:我已委托"维权骑士"(rightknights.com)为我的文章进行维权行动.转载务必转载 ...
- Android TV开发中所有的遥控器按键监听及注意事项,新增home键监听
原文:Android TV开发中所有的遥控器按键监听及注意事项,新增home键监听 简单记录下android 盒子开发遥控器的监听 ,希望能帮到新入门的朋友们 不多说,直接贴代码 public cla ...
- Android TV开发总结(四)通过RecycleView构建一个TV app列表页(仿腾讯视频TV版)
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52854131 前言:昨晚看锤子手 ...
- Android TV开发总结(二)构建一个TV Metro界面(仿泰捷视频TV版)
前言:上篇是介绍构建TV app前要知道的一些事儿,开发Android TV和手机本质上没有太大的区别,屏大,焦点处理,按键处理,是有别于有手机和Pad的实质区别.今天来介绍TV中Metro UI风格 ...
- Android TV开发总结(一)构建一个TV app前要知道的事儿
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52792562 前言:近年来,智能 ...
随机推荐
- 为工具箱添加CSKin选项卡
如何使用CSKin 项目的引用→右键→添加; 找到SCKin.dll; 添加引用 工具箱新建一个选项卡; 工具箱的空白处→右键→添加选项卡→SKinControl, 将刚才的CSKin.dll 直接拖 ...
- python's eleventh day for me
python2 中没有nonlocal. 函数名是什么? 函数名就是函数的名字, 本质:变量,特殊的变量. 1.单独打印函数名: def func(): print(666) print(func) ...
- 优化深度神经网络(二)优化算法 SGD Momentum RMSprop Adam
Coursera吴恩达<优化深度神经网络>课程笔记(2)-- 优化算法 深度机器学习中的batch的大小 深度机器学习中的batch的大小对学习效果有何影响? 1. Mini-batch ...
- 什么是DA控制
液压系统中的DA控制: Automotive Drive control & Anti stall control 自动变速控制 & 防熄火控制 (DA控制) 1:自动(变速)驱动控制 ...
- js中slice,splice和split方法的区别
1.slice(数组) 用法:array.slice(start,end) 解释:该方法是对数组进行部分截取,并返回一个数组副本:参数start是截取的开始数组索引,end参数等于你要取的最后一个字符 ...
- Borland.Delphi.dll
Borland.Delphi.dll Borland Delphi Runtime for .NET Imports Borland.DelphiImports Borland.Delphi.Unit ...
- love 玫瑰花
<!doctype html> <html> <head> <title>Love</title> <meta charset=&qu ...
- java5 Condition用法--实现线程间的通信
Condition的功能类似在传统线程技术中的Object.wait()和Object.natify()的功能,传统线程技术实现的互斥只能一个线程单独干,不能说这个线程干完了通知另一个线程来干,Con ...
- python调用Go代码
Go 1.5发布了,其中包含了一个特性:可以编译生成动态链接库,经试验,生成的.so文件可以被python加载并调用.下面举个例子: 先写一个go文件main.go: package main imp ...
- Leetcode:Container With Most Water分析和实现
题目大意是提供n个非负整数,a1,...,an,可以将其理解为多个边界(垂直的线段),其中ai处于x坐标i处,并且ai代表的线段高度即为ai的值.要求我们取这样的i与j,使得ai与aj以及x坐标轴围成 ...