TV电视和机顶盒都有一个获得焦点时放大效果,这是很常见的,最近也在做盒子和TV开发,研究了一下,这里给出源码和效果,后面会给出具体分析和计算公式。
1.item获得焦点时放大倍数和事件处理:
【AndroidTV开发2------实现Item选中放大效果】
文章图片
/**
* item获得焦点时调用
*
* @param itemView view
*/
private void focusStatus(View itemView,int position) {
if (itemView == null) {
return;
}float scal;
scal = 1.8f;
if (Build.VERSION.SDK_INT >= 21) {
//抬高Z轴
ViewCompat.animate(itemView).scaleX(scal).scaleY(scal).translationZ(1.1f).start();
} else {
ViewCompat.animate(itemView).scaleX(scal).scaleY(scal).start();
ViewGroup parent = (ViewGroup) itemView.getParent();
parent.requestLayout();
parent.invalidate();
}
onItemFocus(itemView);
}
2.item失去焦点的处理:
文章图片
/**
* item失去焦点时
*
* @param itemView item对应的View
*/
private void normalStatus(View itemView) {
if (itemView == null) {
return;
}
if (Build.VERSION.SDK_INT >= 21) {
ViewCompat.animate(itemView).scaleX(1.0f).scaleY(1.0f).translationZ(0).start();
} else {
ViewCompat.animate(itemView).scaleX(1.0f).scaleY(1.0f).start();
ViewGroup parent = (ViewGroup) itemView.getParent();
parent.requestLayout();
parent.invalidate();
}
onItemGetNormal(itemView);
}
3.GameListAdapter完整代码如下:
package com.example.tvrecyclerview.adapter;
import android.content.Context;
import android.os.Build;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.example.tvrecyclerview.R;
import com.example.tvrecyclerview.bean.GameListBean;
import com.example.tvrecyclerview.util.GlideUtils;
import java.util.List;
/**
* @author: njb
* @date: 2020/6/22 0022 0:54
* @desc:
*/
public abstract class GameListAdapter extends RecyclerView.Adapter {
private List mList;
private Context mContext;
private OnItemFocusChangeListener mOnFocusChangeListener;
private OnItemClickListener mOnItemClickListener;
private final LayoutInflater mLayoutInflater;
public GameListAdapter(List mList,Context context,OnItemClickListener onItemClickListener) {
this.mList = mList;
this.mContext = context;
mLayoutInflater = LayoutInflater.from(mContext);
this.mOnItemClickListener = onItemClickListener;
}public void setData(List gameListBeans) {
this.mList = gameListBeans;
notifyDataSetChanged();
}public interface OnItemClickListener {
void onItemClick(View view, int position);
}public interface OnItemFocusChangeListener {
void onItemFocusChange(View view, int position, boolean hasFocus);
}public final void setOnItemClickListener(@Nullable OnItemClickListener listener) {
mOnItemClickListener = listener;
}public void setOnFocusChangeListener(@Nullable OnItemFocusChangeListener mOnFocusChangeListener) {
this.mOnFocusChangeListener = mOnFocusChangeListener;
}@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = mLayoutInflater.inflate(R.layout.listview_item,parent, false);
return new RecyclerViewHolder(v);
}@Override
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, final int position) {
final RecyclerViewHolder viewHolder = (RecyclerViewHolder) holder;
viewHolder.tv.setText(mList.get(position).getGameName());
GlideUtils.loadImg(mContext,mList.get(position).getImg(),viewHolder.iv);
if (mOnItemClickListener != null) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mOnItemClickListener.onItemClick(v, position);
}
});
}
holder.itemView.setFocusable(true);
holder.itemView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if(hasFocus){
focusStatus(v,holder.getAdapterPosition());
}else {
normalStatus(v);
}
}
});
holder.itemView.setOnHoverListener(new View.OnHoverListener() {
@Override
public boolean onHover(View v, MotionEvent event) {
int what =event.getAction();
switch (what) {
case MotionEvent.ACTION_HOVER_ENTER:
RecyclerView recyclerView = (RecyclerView) holder.itemView.getParent();
int[] location = new int[2];
recyclerView.getLocationOnScreen(location);
int x = location[0];
//LogUtil.i("swj","GalleryAdapter.onHover.x="+x +",width = "+(recyclerView.getWidth()+x));
//为了防止滚动冲突,在滚动时候,获取焦点为了显示全,会回滚,这样会导致滚动停止
if (recyclerView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE) {
//当超出RecyclerView的边缘时不去响应滚动
if (event.getRawX() > recyclerView.getWidth() + x || event.getRawX() < x) {
return true;
}
//鼠标进入view,争取到焦点
v.requestFocusFromTouch();
v.requestFocus();
//LogUtil.i(this,"HomeTvAdapter.onHover.position:"+position);
focusStatus(v, holder.getAdapterPosition());
}
break;
case MotionEvent.ACTION_HOVER_MOVE://鼠标在view上移动
break;
case MotionEvent.ACTION_HOVER_EXIT://鼠标离开view
normalStatus(v);
break;
}
return false;
}
});
}@Override
public int getItemCount() {
return mList.size();
}private class RecyclerViewHolder extends RecyclerView.ViewHolder {
TextView tv;
ImageView iv;
RecyclerViewHolder(View itemView) {
super(itemView);
tv = (TextView) itemView.findViewById(R.id.tv_name);
iv = (ImageView) itemView.findViewById(R.id.iv_bg);
}
}/**
* item获得焦点时调用
*
* @param itemView view
*/
private void focusStatus(View itemView,int position) {
if (itemView == null) {
return;
}float scal;
scal = 1.8f;
if (Build.VERSION.SDK_INT >= 21) {
//抬高Z轴
ViewCompat.animate(itemView).scaleX(scal).scaleY(scal).translationZ(1.1f).start();
} else {
ViewCompat.animate(itemView).scaleX(scal).scaleY(scal).start();
ViewGroup parent = (ViewGroup) itemView.getParent();
parent.requestLayout();
parent.invalidate();
}
onItemFocus(itemView);
}/**
* 当item获得焦点时处理
*
* @param itemView itemView
*/
protected abstract void onItemFocus(View itemView);
/**
* item失去焦点时
*
* @param itemView item对应的View
*/
private void normalStatus(View itemView) {
if (itemView == null) {
return;
}
if (Build.VERSION.SDK_INT >= 21) {
ViewCompat.animate(itemView).scaleX(1.0f).scaleY(1.0f).translationZ(0).start();
} else {
ViewCompat.animate(itemView).scaleX(1.0f).scaleY(1.0f).start();
ViewGroup parent = (ViewGroup) itemView.getParent();
parent.requestLayout();
parent.invalidate();
}
onItemGetNormal(itemView);
}/**
* 当条目失去焦点时调用
*
* @param itemView 条目对应的View
*/
protected abstract void onItemGetNormal(View itemView);
}
4.MainActivity代码:
package com.example.tvrecyclerview;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.example.tvrecyclerview.adapter.GameListAdapter;
import com.example.tvrecyclerview.adapter.MyRecycleViewAdapter;
import com.example.tvrecyclerview.bean.GameListBean;
import com.example.tvrecyclerview.util.ScreenUtil;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements MyRecycleViewAdapter.OnItemClickListener,MyRecycleViewAdapter.OnItemFocusChangeListener {
private MyRecycleViewAdapter adapter;
private RecyclerView recyclerView, rvGameList;
//标题
private String[] titles = {"首页", "游戏", "教育", "生活", "娱乐", "新闻", "直播", "我的"};
private GameListAdapter gameListAdapter;
private List gameListBeans;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initAdapter();
initGameListAdapter();
}private void initGameListAdapter() {
setData();
gameListAdapter = new GameListAdapter(gameListBeans, this, new GameListAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {}
}) {
@Override
protected void onItemFocus(View itemView) {
itemView.setSelected(true);
View view = itemView.findViewById(R.id.iv_bg);
view.setSelected(true);
}@Override
protected void onItemGetNormal(View itemView) {
itemView.setSelected(true);
View view = itemView.findViewById(R.id.iv_bg);
view.setSelected(true);
}
};
rvGameList.setLayoutManager(new GridLayoutManager(this,4));
rvGameList.addItemDecoration(new RecyclerView.ItemDecoration() {
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.top= ScreenUtil.dp2px(MainActivity.this,20);
}
});
rvGameList.setAdapter(gameListAdapter);
}/**
* 初始化view
*/
private void initView() {
recyclerView = findViewById(R.id.rv_tab);
rvGameList = findViewById(R.id.rv_game_list);
}/**
* 初始化Adapter
*/
private void initAdapter() {
adapter = new MyRecycleViewAdapter(this, titles);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setAdapter(adapter);
recyclerView.requestFocus();
adapter.setOnFocusChangeListener(this);
adapter.setOnItemClickListener(this);
}@Override
public void onItemClick(View view, int position) {
updateData(titles[position]);
}private void updateData(String title) {
if (gameListBeans != null && gameListBeans.size() > 0) {
gameListBeans.clear();
}
for (int i = 0;
i < 10;
i++) {
GameListBean gameListBean = new GameListBean();
gameListBean.setGameName(title);
gameListBean.setImg("2");
gameListBeans.add(gameListBean);
}
gameListAdapter.notifyDataSetChanged();
}private void setData() {
gameListBeans = new ArrayList<>();
for (int i = 0;
i < 6;
i++) {
GameListBean gameListBean = new GameListBean();
gameListBean.setGameName("王者荣耀");
gameListBean.setImg("2");
gameListBeans.add(gameListBean);
}
}@Override
public void onItemFocusChange(View view, int position, boolean hasFocus) {
}
}
5.实现的效果图如下:
文章图片
6.这里的数据都是模拟假数据,小伙伴们如需真实数据可以写一个WanAndroidTV版,最后项目的源码完整地址如下:
https://gitee.com/jackning_admin/TvRecyclerView