AndroidTV开发2------实现Item选中放大效果

TV电视和机顶盒都有一个获得焦点时放大效果,这是很常见的,最近也在做盒子和TV开发,研究了一下,这里给出源码和效果,后面会给出具体分析和计算公式。
1.item获得焦点时放大倍数和事件处理:
【AndroidTV开发2------实现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失去焦点的处理:
AndroidTV开发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.实现的效果图如下:
AndroidTV开发2------实现Item选中放大效果
文章图片

6.这里的数据都是模拟假数据,小伙伴们如需真实数据可以写一个WanAndroidTV版,最后项目的源码完整地址如下:
https://gitee.com/jackning_admin/TvRecyclerView

    推荐阅读