Android TV列表获取焦点item放大

fragment_test.xml

<!-- recyclerview的item有获取焦点放大效果,为了不让item放大后边缘被遮挡,recyclerview的父布局要添加
	android:clipChildren="false"和android:clipToPadding="false"
 -->
<?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:baselineAligned="false"
    android:clipChildren="false" 
    android:clipToPadding="false"
    android:orientation="horizontal">

	<!-- MenuItem -->
	<!-- 要item选中修改焦点,需要实现setOnItemSelectListener.onItemSelect()处理 -->
    <!--<ListView
        	android:id="@+id/lv_menu_item"
        	android:layout_width="0dp"
        	android:layout_height="match_parent"
        	android:layout_weight="0.3"
        	android:background="@color/colorPrimary"
        	android:paddingTop="50dp" />
	-->

	<!-- 指定listSelector的item选中时的背景 -->
	<ListView
		android:id="@+id/lv_menu_item"
		android:layout_width="0dp"
		android:layout_height="match_parent"
		android:layout_weight="0.3"
		android:background="@color/colorPrimary"
		android:listSelector="@drawable/menu_item_focus_bg"
		android:focusable="false" />

	<!-- CardItem -->
    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_card_content"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:layout_margin="15dp" />

</LinearLayout>

menu_item_list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
	android:descendantFocusability="blocksDescendants" // 让item比ListView先获取到焦点
    android:padding="20dp">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@mipmap/ic_launcher_round"
        tools:ignore="contentDescription" />

    <TextView
        android:id="@+id/tv_menu_item"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:textColor="@android:color/white"
        android:textSize="20sp"
        tools:text="Row Fragment" />
</LinearLayout>

card_content_list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:focusable="true"  // recyclerview的item要设置focusable=true,方便监听setOnFocusChangeListener
    android:layout_margin="10dp"
    app:cardBackgroundColor="@color/colorAccent"
    app:cardCornerRadius="5dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <ImageView
            android:layout_width="150dp"
            android:layout_height="150dp"
            android:background="@mipmap/ic_launcher"
            tools:ignore="contentDescription" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="5dp"
            android:textColor="@android:color/white"
            android:textSize="13sp"
            android:text="Meerirgendwas" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="5dp"
            android:textColor="@android:color/tertiary_text_light"
            android:textSize="12sp"
            android:text="$3.00/lb" />
    </LinearLayout>
</android.support.v7.widget.CardView>

menu_item_focus_bg.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_focus="true">
		<shape>
			<stroke 
				android:width="2dp"
				android:color="@color/colorAccent"/>
		</shape>
	</item>
	<item android:state_focus="false">
		<shape>
			<stroke
				android:width="2dp"
				android:color="@android:color/transparent"/>
		</shape>
	</item>
	<item>
		<shape>
			<stroke
				android:width="2dp"
				android:color="@android:color/transparent"/>
		</shape>
	</item>
</selector>

card_content_focus_bg.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="@color/colorAccent"/>
    <stroke
        android:width="2dp"
        android:color="@android:color/white"/>
</shape>

MenuItemAdapter.java

package com.example.customleanback.normal;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import com.example.customleanback.R;

import java.util.List;

public class MenuItemAdapter extends BaseAdapter {
    private Context mContext;
    private LayoutInflater mInflater;
    private List<String> mMenuItemList;
    private int mSelectedPosition;

    public MenuItemAdapter(Context context, List<String> menuItemList) {
        this.mContext = context;
        this.mInflater = LayoutInflater.from(context);
        this.mMenuItemList = menuItemList;
    }

    @Override
    public int getCount() {
        return mMenuItemList.size();
    }

    @Override
    public String getItem(int position) {
        return mMenuItemList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        final HeaderTitleViewHolder viewHolder;
        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.menu_item_list_item, parent, false);
            viewHolder = new HeaderTitleViewHolder();
            viewHolder.tvMenuItem = convertView.findViewById(R.id.tv_menu_item);
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (HeaderTitleViewHolder) convertView.getTag();
        }

        viewHolder.tvMenuItem.setText(mMenuItemList.get(position));

		// 如果ListView或GridView没有设置listSelector属性指定背景就这样处理item获取焦点时背景转换
        if (mSelectedPosition == position) {
            convertView.setBackgroundResource(R.drawable.menu_item_focus_bg);
        } else {
            convertView.setBackgroundResource(0);
        }

        return convertView;
    }

	// 监听setOnItemSelectedListener,选中获取到焦点时通知item更新背景
    public void setSelected(int position) {
        mSelectedPosition = position;
        notifyDataSetChanged();
    }

    private static class HeaderTitleViewHolder {
        TextView tvMenuItem;
    }
}

CardContentAdapter.java

package com.example.customleanback.normal;

import android.content.Context;
import android.os.Build;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.example.customleanback.R;
import com.example.customleanback.utils.AnimationUtils;

import java.util.List;

public class CardContentAdapter extends RecyclerView.Adapter<CardContentAdapter.ContentViewHolder> {
    private LayoutInflater mInflater;
    private List<String> mCardContentList;

    public CardContentAdapter(Context context, List<String> cardContentList) {
        this.mInflater = LayoutInflater.from(context);
        this.mCardContentList = cardContentList;
    }

    @Override
    public ContentViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new ContentViewHolder(mInflater.inflate(R.layout.card_content_list_item, parent, false));
    }

    @Override
    public void onBindViewHolder(final ContentViewHolder holder, int position) {
		// 监听遥控器ok确认键
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mOnItemClickListener != null) {
                    mOnItemClickListener.onItemClick(holder.itemView, holder.getAdapterPosition());
                }
            }
        });
		// 监听item获取焦点修改背景和item放大
        holder.itemView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                float scaleX = hasFocus ? 1.15f : 1f;
                float scaleY = hasFocus ? 1.15f : 1f;
                AnimationUtils.focusScale(v, scaleX, scaleY);
                holder.itemView.setBackgroundResource(
                        hasFocus ? R.drawable.card_content_focus_bg : R.color.colorAccent);
            }
        });
    }

    @Override
    public int getItemCount() {
        return mCardContentList.size();
    }

    public static class ContentViewHolder extends RecyclerView.ViewHolder {

        public ContentViewHolder(View itemView) {
            super(itemView);
        }
    }

    private OnItemClickListener mOnItemClickListener;

    public void setOnItemClickListener(OnItemClickListener listener) {
        this.mOnItemClickListener = listener;
    }

    public interface OnItemClickListener {
        void onItemClick(View view, int position);
    }
}

AnimationUtils.java

package com.example.customleanback.utils;

import android.os.Build;
import android.support.v4.view.ViewCompat;
import android.view.View;
import android.view.ViewGroup;

public class AnimationUtils {

    public static void focusScale(View view, float scaleX, float scaleY) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            ViewCompat.animate(view)
                    .scaleX(scaleX)
                    .scaleY(scaleY)
                    .translationZ(1)
                    .start();
        } else {
            ViewCompat.animate(view)
                    .scaleX(scaleX)
                    .scaleY(scaleY)
                    .start();
            ViewGroup parent = (ViewGroup) view.getParent();
            parent.requestLayout();
            parent.invalidate();
        }
    }
}

TestFragment.java

package com.example.customleanback.normal;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;

import com.example.customleanback.R;

import java.util.ArrayList;
import java.util.List;

/**
 * 1、ListView、GridView的item不能设置focusable=true,否则无法响应onItemClickListener
 *
 * 2、ListView、GridView的item焦点监听:
 * 方法1:ListView.setOnItemSelectedListener、GridView.setOnItemSelectedListener,在callback刷新列表内容
 * 方法2:在xml文件中设置ListView或GridView的listSelector指定item选中时的背景
 *
 * 3、RecyclerView的item根布局要设置focusable=true,才能监听holder.itemView.setOnFocusChangeListener
 *
 * 4、添加获取焦点放大item时,为了防止边缘被遮挡,在xml中RecyclerView的ViewGroup布局添加clipToPadding=false和clipChildren=false
 *
 * 5、遥控器控制上下左右时,比如ListView按下右键切换到RecyclerView获取焦点,或者RecyclerView按左键切换到ListView,
 * 焦点的选中时随机的,会让距离当前view最近的view获取焦点
 *
 * 6、为了防止焦点乱跑,可以监听setOnKeyListener拦截事件处理
 */
public class TestFragment extends Fragment {
    private ListView mLvMenuItem;
    private RecyclerView mRvCardContent;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_test, container, false);
        mLvMenuItem = rootView.findViewById(R.id.lv_menu_item);
        mRvCardContent = rootView.findViewById(R.id.rv_card_content);
        return rootView;
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        setupMenuItem();
        setupCardContent();
    }

    private void setupCardContent() {
        List<String> contentList = new ArrayList<>();
        for (int i = 0; i < 15; i++) {
            contentList.add("item" + i);
        }
        mRvCardContent.setHasFixedSize(true);
        mRvCardContent.setLayoutManager(new GridLayoutManager(getContext(), 4));
        CardContentAdapter cardContentAdapter = new CardContentAdapter(getContext(), contentList);
        mRvCardContent.setAdapter(cardContentAdapter);

        // 响应遥控器ok确认键点击
        cardContentAdapter.setOnItemClickListener(new CardContentAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                Toast.makeText(getContext(), "click position " + position, Toast.LENGTH_SHORT).show();
            }
        });
    }

    private void setupMenuItem() {
        List<String> menuItemList = new ArrayList<>();
        menuItemList.add("Page Fragment");
        menuItemList.add("Row Fragment");
        menuItemList.add("Settings Fragment");
        menuItemList.add("User Agreement Fragment");
        final MenuItemAdapter menuItemAdapter = new MenuItemAdapter(getContext(), menuItemList);
        mLvMenuItem.setAdapter(menuItemAdapter);

        // 响应遥控器ok确认点击
        mLvMenuItem.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Toast.makeText(getContext(), "click position " + position, Toast.LENGTH_SHORT).show();
            }
        });
        // 响应遥控器上下左右按键获取焦点
		// 如果ListView或GridView已经设置了listSelector修改item背景,一般写该监听是要处理item选中时的其他逻辑
        mLvMenuItem.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                // menuItemAdapter.setSelected(position);
				// 其他逻辑
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {

            }
        });
        // 拦截遥控器右键,自动选中RecyclerView第一个位置,防止焦点乱跑
        mLvMenuItem.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
                    mRvCardContent.requestFocus();
                    mRvCardContent.smoothScrollToPosition(0);
                    return true;
                }
                return false;
            }
        });
    }
}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值