前言:
本質(zhì)和移動端開發(fā)沒有什么區(qū)別,只是要處理遙控器的按鍵以及焦點。目前我知道有兩種技術(shù)路徑一種使用leanback,一種使用普通移動端的開發(fā)方式只不過焦點需要自己處理。
1、頁面隱藏狀態(tài)欄
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
2、組件放大動畫
package com.fangtao.widget;
import android.animation.ValueAnimator;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
public class FocusUtil {
private final static int duration = 140;
private final static float startScale = 1.0f;
//private final static float endScale = 1.14f;
public static final float SCALE_RATE = 1.045f;//一
// public static final float SCALE_RATE = 1.0571f;
/**
* 當(dāng)焦點發(fā)生變化
*
* @param view
* @param gainFocus
*/
public static void onFocusChange(View view, boolean gainFocus) {
if (gainFocus) {
onFocusIn(view,SCALE_RATE);
} else {
onFocusOut(view,SCALE_RATE);
}
}
/**
* 當(dāng)view獲得焦點
*
* @param view
*/
public static void onFocusIn(final View view,float endScale) {
ValueAnimator animIn = ValueAnimator.ofFloat(startScale, endScale);
animIn.setDuration(duration);
animIn.setInterpolator(new DecelerateInterpolator());
animIn.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (Float) animation.getAnimatedValue();
view.setScaleX(value);
view.setScaleY(value);
}
});
animIn.start();
}
/**
* 當(dāng)view失去焦點
*
* @param view
*/
public static void onFocusOut(final View view,float endScale) {
ValueAnimator animOut = ValueAnimator.ofFloat(endScale, startScale);
animOut.setDuration(duration);
animOut.setInterpolator(new DecelerateInterpolator());
animOut.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (Float) animation.getAnimatedValue();
view.setScaleX(value);
view.setScaleY(value);
}
});
animOut.start();
}
}
//使用
FocusUtil.onFocusIn(view, 1.28f);
3、實現(xiàn)基礎(chǔ)布局的圓角
在drawable中編寫對應(yīng)的xml來實現(xiàn)
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/greed" /> <!-- 背景顏色,這里設(shè)置為透明 -->
<!-- 邊框?qū)挾?-->
<!-- 邊框顏色 -->
<!-- <stroke-->
<!-- android:width="2dp"-->
<!-- android:color="#9CFFFFFF" />-->
<corners
android:radius="20dp" /> <!-- 圓角半徑,根據(jù)需要進行調(diào)整 -->
</shape>
4、實現(xiàn)輪播功能
開源組件:Android輪播(banner)組件的使用 - 簡書
5、實現(xiàn)基礎(chǔ)布局的漸變色背景
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:angle="90"
android:endColor="@color/colorPrimary"
android:startColor="@color/colorAccent" />
</shape>
獲取焦點和失去焦點改變透明度
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true">
<shape>
<solid android:color="#FF000000" /> <!-- 完全不透明 -->
</shape>
</item>
<item>
<shape>
<solid android:color="#B2000000" /> <!-- 半透明 -->
</shape>
</item>
</selector>
6、實現(xiàn)videoView組件圓角顯示
①使用cardView,這種方式四個角都是圓角,無法單獨設(shè)置每一個圓角
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="5dp"
app:cardElevation="0dp"
app:contentPadding="0dp"
>
<VideoView
android:id="@+id/video"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.cardview.widget.CardView>
②其他方式,暫時沒有
7、實現(xiàn)圖片圓角
①使用第三方圖片組件
參考:Android的ImageView必知必會 - 簡書
②使用Glide
RequestOptions options = new RequestOptions()
.placeholder(R.drawable.cache)
.circleCropTransform();
GlideApp.with(FangTaoTvApplication.getInstance())
.load(merchantInfoModel.getPicture())
.placeholder(R.drawable.pic_loading)
.apply(options)
.into(logoImg);
8、布局
參考:約束布局ConstraintLayout看這一篇就夠了 - 簡書
9、本地緩存工具
參考:Android本地保存實用工具SpUtil 對SharedPreferences的簡單封裝_android開發(fā)中sp工具類
public class SpUtil{
private final SharedPreferences sharedPreferences;
private final SharedPreferences.Editor editor;
private final Gson gson;
private static SpUtil spUtil;
private SpUtil(Context context){
sharedPreferences = context.getSharedPreferences("sp_data",Context.MODE_PRIVATE);
editor = sharedPreferences.edit();
gson = new Gson();
}
public static SpUtilgetInstance (Context context){
if (spUtil == null){
spUtil = new SpUtil(context);
}
return spUtil;
}
}
//保存
public void putInt(String key, int num){
editor.putInt(key, num);
editor.apply();
}
public void putString(String key, String content){
editor.putString(key, content);
editor.apply();
}
public void putBoolean(String key, boolean value){
editor.putBoolean(key, value);
editor.apply();
}
public void putLong(String key, long value){
editor.putLong(key, value);
editor.apply();
}
//讀取
public int getInt(String key){
return sharedPreferences.getInt(key, 0);
}
public String getString(String key){
return sharedPreferences.getString(key,"");
}
public boolean getBoolean(String key){
return sharedPreferences.getBoolean(key,false);
}
public long getLong(String key){
return sharedPreferences.getLong(key,0);
}
//保存對象
public void putObject(String key, Object obj){
String json = gson.toJson(obj);
putString(key, json);
}
//獲取對象
public <T> T getObject(String key, Class<T> clazz){
String json = getString(key);
if (TextUtils.isEmpty(json)){
return null;
}
return gson.fromJson(json, clazz);
}
//刪除對象
public void removeObject(String key){
editor.remove(key);
editor.apply();
}
//保存列表
public void putObjList(String key, List objectList){
String json = gson.toJson(objectList);
putString(key, json);
}
//獲取列表
public <T> List<T> getObjList(String key){
List<T> list;
String json = getString(key);
if (TextUtils.isEmpty(json)){
return null;
}
list = gson.fromJson(json, new TypeToken<List<T>>(){}.getType());
return list;
}
/**
* 將map集合轉(zhuǎn)化為json數(shù)據(jù)保存在sharePreferences中
*
* @param key key sharePreferences數(shù)據(jù)Key
* @param map map數(shù)據(jù)
* @return 保存結(jié)果
*/
public <K,V> boolean putMap(String key , Map<K,V> map){
boolean result;
try {
String json = gson.toJson(map);
editor.putString(key , json);
editor.apply();
result = true;
}catch (Exception e){
result = false;
e.printStackTrace();
}
return result;
}
/**
* 從本地獲取保存的map數(shù)據(jù)
* 缺點:將Integer默認轉(zhuǎn)化為Double
* */
public <K,V> HashMap<K,V> getMap(String key){
String mapJson = getString(key);
if (TextUtils.isEmpty(mapJson)){
return null;
}
return gson.fromJson(mapJson, new TypeToken<HashMap<K,V>>(){}.getType());
}
基本使用
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SpUtil spUtil= SpUtil.getInstance(this);
//簡單類型存取
spUtil.putInt("first", 1);
spUtil.getInt("first");
//hashMap存取
HashMap<String , Integer> map = new HashMap<>();
map.put("鐵柱",30);
map.put("小鳳",28);
map.put("阿珍",26);
map.put("阿強",27);
if (spUtil.putMap("MAP_DATA",map)){
HashMap<String , Integer> hashMap = spUtil.getMap("MAP_DATA");
if (hashMap != null ){
spUtil.showMapData(hashMap);
}
}else {
Log.e(TAG, "1111" );
}
}
10、常用監(jiān)聽
①焦點監(jiān)聽
//搜索
flTopSearch.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View view, boolean b) {
if(b) { //選中圖片
GlideApp.with(MainActivity.getActivity()).asDrawable()
.load(R.drawable.home_search_icon_select_v6)
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.into(new ImageViewTarget<Drawable>(ivSearchIcon) {
@Override
protected void setResource(@Nullable Drawable resource) { if(resource!=null) {
ivSearchIcon.setImageDrawable(resource);
}
}
});
}else{ //未選中圖片
GlideApp.with(MainActivity.getActivity()).asDrawable()
.load(R.drawable.home_search_icon_unselect_v6)
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.into(new ImageViewTarget<Drawable>(ivSearchIcon) {
@Override
protected void setResource(@Nullable Drawable resource) { if(resource!=null) {
ivSearchIcon.setImageDrawable(resource);
}
}
});
}
}
});
②遙控器按鍵監(jiān)聽
cflVideo.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View view, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_LEFT:
View view1 = findViewById(R.id.cfl_banner);
view1.requestFocus();
view1.setFocusable(true);
view1.setFocusableInTouchMode(true);
return true;
case KeyEvent.KEYCODE_DPAD_RIGHT:
CustomFrameLayout layout = findViewById(R.id.qcode);
layout.requestFocus();
layout.setFocusable(true);
layout.setFocusableInTouchMode(true);
return true;
case KeyEvent.KEYCODE_DPAD_UP:
TextView button = findViewById(R.id.cfl_my_top_day_update);
button.requestFocus();
button.setFocusable(true);
button.setFocusableInTouchMode(true);
return true;
case KeyEvent.KEYCODE_DPAD_DOWN:
CustomFrameLayout layout1 = findViewById(R.id.cfl_all_commodity);
layout1.requestFocus();
layout1.setFocusable(true);
layout1.setFocusableInTouchMode(true);
return true;
case KeyEvent.KEYCODE_DPAD_CENTER:
if(MusicService.getService().getStatus()){
MusicService.getService().pause();
}
Intent intent = new Intent(MainActivity.this, FullVideoActivity.class);
intent.putExtra("videoUrl",re);
intent.putExtra("type", type);
startActivity(intent);
return true;
case KeyEvent.KEYCODE_BACK:
break;
}
}
return false;
}
});
11、代碼中選中組件
cflAllGoods.requestFocus();
cflAllGoods.setFocusable(true); //可以被按鍵選中
cflAllGoods.setFocusableInTouchMode(true); //可以被觸摸選中