您当前的位置: 首页 >  android

Kevin-Dev

暂无认证

  • 0浏览

    0关注

    544博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

【Android TV 开发】-->Leanback 中的 VerticalGridView

Kevin-Dev 发布时间:2022-04-18 16:55:26 ,浏览量:0

不断学习,做更好的自己!💪

视频号CSDN简书欢迎打开微信,关注我的视频号:KevinDev点我点我

LeanBack 是 Google 官方推出的 TV 端的功能库,里面包含了很多在 TV Android 端开发常用的控件,本文重点介绍其对 RecyclerView 适配 TV 端做的封装:VerticalGridView 。

效果图

在这里插入图片描述

属性 & 方法
  • focusOutFront、focusOutEnd 如果标题栏使用 HorizontalGridView 实现,内容区域使用 Fragment 里放的 VerticalGridView 实现,可能出现标题栏和内容区焦点切换不成功的问题,比如说,焦点不能从内容区切到标题栏这样的情况。这时使用 focusOutFront 和 focusOutEnd 属性能够解决问题,解决不同容器里焦点切换不成功的问题。

  • setHorizontalSpacing(),setVerticalSpacing() 设置 VerticalGridView 的 Item 之间的间距。

  • setNumColumns() 设置列数,默认 VerticalGridView 为一列,通过 setNumColumns 方法可以设置多列。但有个注意点,设置多行后要注意 position 的位置。

基本使用

1. 添加依赖

	implementation 'androidx.leanback:leanback:1.0.0'
    implementation 'androidx.leanback:leanback-preference:1.0.0'

2. 布局文件




    

    

    


3. AppVerticalGridView.java

public class AppVerticalGridView extends VerticalGridView {
    private static final String TAG = "AppVerticalGridView";
    private int mNumColumns;

    public AppVerticalGridView(Context context) {
        this(context, null);
    }

    public AppVerticalGridView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public AppVerticalGridView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public void setColumnNumbers(int numColumns) {
        this.mNumColumns = numColumns;
        setNumColumns(numColumns);
    }

    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (event.getAction() == KeyEvent.ACTION_DOWN) {
            switch (event.getKeyCode()) {
                case KeyEvent.KEYCODE_BACK:
                    if (getSelectedPosition() > 0) {
                        setSelectedPosition(0);
                        return true;
                    }
                    break;
                case KeyEvent.KEYCODE_DPAD_DOWN:

                    if (mNumColumns == 0 || getAdapter() == null) {
                        break;
                    }

                    int itemCount = getAdapter().getItemCount();
                    if (itemCount + 1  itemCount)) {
                        setSelectedPositionSmooth(itemCount - 1);
                        return true;
                    }
                    break;
            }

        }
        return super.dispatchKeyEvent(event);
    }
}

4. Bean 类

public class HomeAppModel {
    public String dataDir;
    public Drawable icon;
    public String id;
    public String name;
    public String launcherName;
    public String packageName;
    public int pageIndex;
    public int position;
    public boolean sysApp;

    public String getDataDir() {
        return this.dataDir;
    }

    public Drawable getIcon() {
        return this.icon;
    }

    public String getId() {
        return this.id;
    }

    public String getName() {
        return this.name;
    }

    public String getPackageName() {
        return this.packageName;
    }

    public int getPageIndex() {
        return this.pageIndex;
    }

    public int getPosition() {
        return this.position;
    }

    public void setDataDir(String paramString) {
        this.dataDir = paramString;
    }

    public void setIcon(Drawable paramDrawable) {
        this.icon = paramDrawable;
    }

    public void setId(String paramString) {
        this.id = paramString;
    }

    public void setName(String paramString) {
        this.name = paramString;
    }

    public void setPackageName(String paramString) {
        this.packageName = paramString;
    }

    public void setPageIndex(int paramInt) {
        this.pageIndex = paramInt;
    }

    public void setPosition(int paramInt) {
        this.position = paramInt;
    }

    public String toString() {
        return "AppBean [packageName=" + this.packageName + ", name=" + this.name + ", dataDir=" + this.dataDir + "]";
    }

    public boolean isSysApp() {
        return sysApp;
    }

    public void setSysApp(boolean sysApp) {
        this.sysApp = sysApp;
    }

    public String getLauncherName() {
        return launcherName;
    }

    public void setLauncherName(String launcherName) {
        this.launcherName = launcherName;
    }
}

5. 创建 Presenter

public class HomePresenter extends Presenter {
    private Context mContext;

    @Override
    public Presenter.ViewHolder onCreateViewHolder(ViewGroup parent) {
        if (mContext == null) {
            mContext = parent.getContext();
        }
        View view = LayoutInflater.from(mContext).inflate(R.layout.item_home_app, parent, false);
        view.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                v.findViewById(R.id.tv_app_name).setSelected(hasFocus);
            }
        });
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
        if (item instanceof HomeAppModel) {
            ViewHolder vh = (ViewHolder) viewHolder;
            if (((HomeAppModel) item).icon != null) {
                Bitmap bitmap = getBitmapFromDrawable(((HomeAppModel) item).icon);//适配Android 8.0
                RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(mContext.getResources(), bitmap);
                drawable.setCornerRadius(DensityUtil.dip2px(mContext, 10));
                vh.mIvAppIcon.setImageDrawable(drawable);
            }
            if (!TextUtils.isEmpty(((HomeAppModel) item).name)) {
                vh.mTvAppName.setText(((HomeAppModel) item).name);
            }
        }
    }

    @Override
    public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {

    }


    public static class ViewHolder extends Presenter.ViewHolder {

        private final ImageView mIvAppIcon;
        private final TextView mTvAppName;

        public ViewHolder(View view) {
            super(view);
            mIvAppIcon = view.findViewById(R.id.iv_app_icon);
            mTvAppName = view.findViewById(R.id.tv_app_name);
        }
    }

    private Bitmap getBitmapFromDrawable(@NonNull Drawable drawable) {
        final Bitmap bmp = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
                drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
        final Canvas canvas = new Canvas(bmp);
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);
        return bmp;
    }
}

6. MyItemBridgeAdapter.java

public abstract class MyItemBridgeAdapter extends ItemBridgeAdapter {
    protected MyItemBridgeAdapter(ObjectAdapter adapter) {
        super(adapter, null);
    }

    @Override
    protected void onBind(final ViewHolder viewHolder) {
        if (getOnItemViewClickedListener() != null) {
            viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    getOnItemViewClickedListener().onItemClicked(v, viewHolder.getViewHolder(),
                            viewHolder.getItem());

                }
            });
            viewHolder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    if (getOnItemViewLongClickedListener() != null) {
                        return getOnItemViewLongClickedListener().onItemLongClicked(v, viewHolder.getViewHolder(),
                                viewHolder.getItem());
                    }
                    return true;
                }
            });
        }
        if (getOnItemFocusChangedListener() != null) {
            viewHolder.itemView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
                @Override
                public void onFocusChange(View v, boolean hasFocus) {
                    getOnItemFocusChangedListener().onItemFocusChanged(v, viewHolder.getViewHolder(),
                            viewHolder.getItem(), hasFocus, viewHolder.getAdapterPosition());
                }
            });
        }
        super.onBind(viewHolder);
    }

    @Override
    protected void onUnbind(ViewHolder viewHolder) {
        super.onUnbind(viewHolder);
        viewHolder.itemView.setOnClickListener(null);
        if (getOnItemFocusChangedListener() != null) {
            viewHolder.itemView.setOnFocusChangeListener(null);
        }
    }

    public abstract OnItemViewClickedListener getOnItemViewClickedListener();

    public OnItemViewLongClickedListener getOnItemViewLongClickedListener() {
        return null;
    }

    public OnItemFocusChangedListener getOnItemFocusChangedListener() {
        return null;
    }

    public interface OnItemViewClickedListener {
        void onItemClicked(View focusView, Presenter.ViewHolder itemViewHolder, Object item);
    }

    public interface OnItemViewLongClickedListener {
        boolean onItemLongClicked(View focusView, Presenter.ViewHolder itemViewHolder, Object item);
    }

    public interface OnItemFocusChangedListener {
        void onItemFocusChanged(View focusView, Presenter.ViewHolder itemViewHolder, Object item, boolean hasFocus, int pos);
    }
}

7. 使用

public class HomeFragment extends BaseFragment {
    @BindView(R.id.vg_app_installed)
    AppVerticalGridView mGridView;

    private ArrayObjectAdapter mAdapter;

    @Override
    protected int layoutId() {
        return R.layout.fragment_home;
    }

    @SuppressLint("RestrictedApi")
    @Override
    protected void initView(View view) {
        mGridView.setNumColumns(6);
        mGridView.setHorizontalSpacing(DensityUtil.dip2px(getActivity(), 53));
        mGridView.setVerticalSpacing(DensityUtil.dip2px(getActivity(), 20));


        mAdapter = new ArrayObjectAdapter(new HomePresenter());
        ItemBridgeAdapter itemBridgeAdapter = new MyItemBridgeAdapter(mAdapter) {
            @Override
            public OnItemViewClickedListener getOnItemViewClickedListener() {
                return new OnItemViewClickedListener() {
                    @Override
                    public void onItemClicked(View focusView,
                                              Presenter.ViewHolder itemViewHolder,
                                              Object item) {
                        if (focusView.hasFocus()
                                && item instanceof HomeAppModel) {

                            try {
                                PackageManager packageManager = getActivity().getPackageManager();
                                Intent intent = packageManager
                                        .getLaunchIntentForPackage(((HomeAppModel) item).packageName);
                                if (intent == null) {
                                    Toast.makeText(getActivity(),
                                            ((HomeAppModel) item).name + "未安装",
                                            Toast.LENGTH_SHORT).show();
                                } else {
                                    startActivity(intent);
                                }
                            } catch (Exception e) {
                                e.printStackTrace();
                            }

                        }
                    }
                };
            }

            @Override
            public OnItemViewLongClickedListener getOnItemViewLongClickedListener() {
                return new OnItemViewLongClickedListener() {
                    @Override
                    public boolean onItemLongClicked(View focusView,
                                                     Presenter.ViewHolder itemViewHolder,
                                                     Object item) {
                        if (focusView.hasFocus()
                                && item instanceof HomeAppModel
                                && !TextUtils.isEmpty(((HomeAppModel) item).packageName)) {
                            Uri packageURI = Uri.parse("package:" + ((HomeAppModel) item).packageName);
                            Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI);
                            uninstallIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                            startActivity(uninstallIntent);
                        }
                        return true;
                    }
                };
            }
        };
        mGridView.setAdapter(itemBridgeAdapter);
        FocusHighlightHelper.setupBrowseItemFocusHighlight(itemBridgeAdapter,
                FocusHighlight.ZOOM_FACTOR_MEDIUM, false);
        initData();
    }

    private void initData() {
        List appInfos = getInstallApps(getContext());
        if (appInfos == null) {
            return;
        }
        mAdapter.addAll(0, appInfos);
    }

    public List getInstallApps(Context context) {
        PackageManager pm = context.getPackageManager();
        List installedPackages = pm.getInstalledPackages(0);  //获取所以已安装的包

        List list = new ArrayList();
        for (PackageInfo packageInfo : installedPackages) {
            Intent intent = pm.getLaunchIntentForPackage(packageInfo.packageName);
            if (intent == null) {
                continue;
            }
            HomeAppModel info = new HomeAppModel();
            ApplicationInfo applicationInfo = packageInfo.applicationInfo;  //应用信息
            info.name = applicationInfo.loadLabel(pm).toString();
            info.icon = applicationInfo.loadIcon(pm);        //状态机,通过01状态来表示是否具备某些属性和功能

            info.packageName = packageInfo.packageName;
            list.add(info);
        }
        Log.e(TAG, "getInstallApps1: ");
        return list;
    }
}
关注
打赏
1658837700
查看更多评论
立即登录/注册

微信扫码登录

0.0595s