AndroidTV自定义软键盘手柄对焦(不使用android默认焦点)

时间:2018-06-13 11:01:38

标签: android android-tv

我正在实现Android智能电视的自定义屏幕键盘,就像 Youtube 一样。我不知道他们是如何创建这个自定义视图的。这是我对这种布局的思考: enter image description here

我完全按照我的想法创建了这个布局。这是我的:

enter image description here

这是我在Github上正在进行的项目。请先试用Youtube版本,然后帮我解决问题。目前,我将所有重点事项留给Android来处理自己(在我的xml中在每个子视图中设置 focusable="true" 。我在这里只处理的是 ENTER_KEY_PAD 被按下。它将在我的布局顶部的Search EditText上显示文本。

我将展示一些代码片段(您可以克隆我的项目以获取更多详细信息)

CustomSoftKeyboardView.java

public class CustomSoftKeyboardView extends FrameLayout {

    private RecyclerView mRvKeys;
    private TextView mTvKeyDelete;
    private TextView mTvKeyClear;
    private TextView mTvKeyNumbers;
    private TextView mTvKeySpace;
    private TextView mTvKeySearch;

    private int mContentLen;
    private StringBuilder mDisplayedText;
    private List<String> mCharacterKeyData;
    private List<String> mNumberKeyData;
    private KeyboardsAdapter mAdapter;
    private View mCurrentFocusedView;
    private View mNextFocusedView;
    private boolean isChangeToNumPads;

    public CustomSoftKeyboardView(@NonNull Context context) {
        super(context);
        initViews();
        initNumberKeyPads();
        initCharacterKeyPads();
        initAdapter(context);
    }

    public CustomSoftKeyboardView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initViews();
        initNumberKeyPads();
        initCharacterKeyPads();
        initAdapter(context);
    }

    public CustomSoftKeyboardView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initViews();
        initNumberKeyPads();
        initCharacterKeyPads();
        initAdapter(context);
    }

    public CustomSoftKeyboardView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initViews();
        initNumberKeyPads();
        initCharacterKeyPads();
        initAdapter(context);
    }


    private void initViews() {
        mDisplayedText = new StringBuilder();
        mContentLen = 0;
        isChangeToNumPads = false;
        View keyboardView = LayoutInflater.from(getContext()).inflate(R.layout.custom_keyboard_item, null);
        mRvKeys = keyboardView.findViewById(R.id.rv_keyPads);
        mTvKeyDelete = keyboardView.findViewById(R.id.tv_keyDelete);
        mTvKeyDelete.setOnFocusChangeListener(new OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (hasFocus) {
                    ViewCompat.setBackground(v, ContextCompat.getDrawable(v.getContext(), R.drawable.pad_background_focus_light_drawable));
                    mTvKeyDelete.setTextColor(Color.WHITE);
                } else {
                    ViewCompat.setBackground(v, null);
                    mTvKeyDelete.setTextColor(Color.BLACK);
                }
            }
        });

        mTvKeyClear = keyboardView.findViewById(R.id.tv_keyClear);
        mTvKeyClear.setOnFocusChangeListener(new OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (hasFocus) {
                    ViewCompat.setBackground(v, ContextCompat.getDrawable(v.getContext(), R.drawable.pad_background_focus_light_drawable));
                    mTvKeyClear.setTextColor(Color.WHITE);
                } else {
                    ViewCompat.setBackground(v, null);
                    mTvKeyClear.setTextColor(Color.BLACK);
                }
            }
        });

        mTvKeyNumbers = keyboardView.findViewById(R.id.tv_keyNumbers);
        mTvKeyNumbers.setText(getContext().getString(R.string.number_pads));
        mTvKeyNumbers.setOnFocusChangeListener(new OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (hasFocus) {
                    ViewCompat.setBackground(v, ContextCompat.getDrawable(v.getContext(), R.drawable.pad_background_focus_light_drawable));
                    mTvKeyNumbers.setTextColor(Color.WHITE);
                } else {
                    ViewCompat.setBackground(v, null);
                    mTvKeyNumbers.setTextColor(Color.BLACK);
                }
            }
        });

        mTvKeySpace = keyboardView.findViewById(R.id.tv_space);
        mTvKeySpace.setOnFocusChangeListener(new OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (hasFocus) {
                    ViewCompat.setBackground(v, ContextCompat.getDrawable(v.getContext(), R.drawable.pad_background_focus_light_drawable));
                    mTvKeySpace.setTextColor(Color.WHITE);
                } else {
                    ViewCompat.setBackground(v, null);
                    mTvKeySpace.setTextColor(Color.BLACK);
                }
            }
        });

        mTvKeySearch = keyboardView.findViewById(R.id.tv_search);
        mTvKeySearch.setOnFocusChangeListener(new OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (hasFocus) {
                    ViewCompat.setBackground(v, ContextCompat.getDrawable(v.getContext(), R.drawable.pad_background_focus_light_drawable));
                    mTvKeySearch.setTextColor(Color.WHITE);
                } else {
                    ViewCompat.setBackground(v, null);
                    mTvKeySearch.setTextColor(Color.BLACK);
                }
            }
        });

        addView(keyboardView);


    }

    private void initCharacterKeyPads() {
        mCharacterKeyData = new ArrayList<>();
        mCharacterKeyData.add("A");
        mCharacterKeyData.add("B");
        mCharacterKeyData.add("C");
        mCharacterKeyData.add("D");
        mCharacterKeyData.add("E");
        mCharacterKeyData.add("F");
        mCharacterKeyData.add("G");
        mCharacterKeyData.add("H");
        mCharacterKeyData.add("I");
        mCharacterKeyData.add("J");
        mCharacterKeyData.add("K");
        mCharacterKeyData.add("L");
        mCharacterKeyData.add("M");
        mCharacterKeyData.add("N");
        mCharacterKeyData.add("O");
        mCharacterKeyData.add("P");
        mCharacterKeyData.add("Q");
        mCharacterKeyData.add("R");
        mCharacterKeyData.add("S");
        mCharacterKeyData.add("T");
        mCharacterKeyData.add("U");
        mCharacterKeyData.add("V");
        mCharacterKeyData.add("W");
        mCharacterKeyData.add("X");
        mCharacterKeyData.add("Y");
        mCharacterKeyData.add("Z");
        mCharacterKeyData.add("-");
        mCharacterKeyData.add("'");
    }

    private void initNumberKeyPads() {
        mNumberKeyData = new ArrayList<>();
        mNumberKeyData.add("1");
        mNumberKeyData.add("2");
        mNumberKeyData.add("3");
        mNumberKeyData.add("&");
        mNumberKeyData.add("#");
        mNumberKeyData.add("(");
        mNumberKeyData.add(")");
        mNumberKeyData.add("4");
        mNumberKeyData.add("5");
        mNumberKeyData.add("6");
        mNumberKeyData.add("@");
        mNumberKeyData.add("!");
        mNumberKeyData.add("?");
        mNumberKeyData.add(":");
        mNumberKeyData.add("7");
        mNumberKeyData.add("8");
        mNumberKeyData.add("9");
        mNumberKeyData.add("0");
        mNumberKeyData.add(".");
        mNumberKeyData.add("_");
        mNumberKeyData.add("\"");
    }

    private void initAdapter(Context context) {
        mAdapter = new KeyboardsAdapter();
        mRvKeys.setAdapter(mAdapter);
        mAdapter.setKeyData(mCharacterKeyData);
        GridLayoutManager gridLayoutManager = new GridLayoutManager(context, 7);
        mRvKeys.setLayoutManager(gridLayoutManager);
    }

    public void reset() {
        if (mDisplayedText.length() > 0) {
            mDisplayedText.delete(0, mDisplayedText.length());
        }
    }


    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (event.getAction() == KeyEvent.ACTION_UP) {
            if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
                View selectedView = findFocus();
                switch (selectedView.getId()) {
                    case R.id.tv_keyDelete:
                        if (mDisplayedText.length() > 0) {
                            mDisplayedText.deleteCharAt(mContentLen);
                            mContentLen = mDisplayedText.length() - 1;
                            EventBus.getDefault().post(new EventDisplayText(mDisplayedText));
                        }
                        break;
                    case R.id.tv_keyClear:
                        if (mDisplayedText.length() > 0) {
                            mDisplayedText.delete(0, mDisplayedText.length());
                            mContentLen = 0;
                            EventBus.getDefault().post(new EventDisplayText(mDisplayedText));
                        }
                        break;
                    case R.id.tv_keyNumbers:
                        if (isChangeToNumPads) {
                            isChangeToNumPads = false;
                            mTvKeyNumbers.setText(getContext().getString(R.string.number_pads));
                            mAdapter.setKeyData(mCharacterKeyData);
                        } else {
                            isChangeToNumPads = true;
                            mTvKeyNumbers.setText(getContext().getString(R.string.character_pads));
                            mAdapter.setKeyData(mNumberKeyData);
                        }
                        break;
                    case R.id.tv_space:
                        mDisplayedText.append(" ");
                        EventBus.getDefault().post(new EventDisplayText(mDisplayedText));
                        break;
                    case R.id.tv_search:
                        if (mDisplayedText.length() > 0) {
                            EventBus.getDefault().post(new EventSearching(mDisplayedText.toString()));
                        }
                        Toast.makeText(getContext(), "PRESS SEARCH", Toast.LENGTH_SHORT).show();
                        break;
                    default:
                        mDisplayedText.append(getKeyPadData(findFocus()));
                        mContentLen = mDisplayedText.length() - 1;
                        EventBus.getDefault().post(new EventDisplayText(mDisplayedText));
                        break;
                }
            }
        }

        return super.dispatchKeyEvent(event);
    }


    private String getKeyPadData(View view) {
        TextView textView = view.findViewById(R.id.tv_keyPad);
        return textView.getText().toString();
    }

} 

MainActivity.java

public class MainActivity extends Activity {

    private EditText mEdtSearch;
    private CustomSoftKeyboardView customSoftKeyboardView;
    private RecyclerView mRvRecentSearches;
    private RecentSearchesAdapter mRecentSearchesAdapter;
    private LinearLayout mRoot;
    private View currentFocusedView;
    private View nextFocusedView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRoot = findViewById(R.id.root);
        getWindow().getDecorView().setBackgroundColor(ContextCompat.getColor(this, R.color.activity_light_bg));
        mEdtSearch = findViewById(R.id.edt_search);
        mRvRecentSearches = findViewById(R.id.rv_recentSearches);
        customSoftKeyboardView = findViewById(R.id.customKeyboardView);
        setUpSuggestionsAdapter();
    }

    private void setUpSuggestionsAdapter() {
        mRecentSearchesAdapter = new RecentSearchesAdapter();
        mRvRecentSearches.setAdapter(mRecentSearchesAdapter);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
        mRvRecentSearches.setLayoutManager(linearLayoutManager);
    }

    private List<String> generateSuggestionsList() {
        List<String> suggestionsList = new ArrayList<>();
        suggestionsList.add("Doraemon");
        suggestionsList.add("Lord of The Rings");
        suggestionsList.add("Hannibal");
        suggestionsList.add("How To Train Your Dragon");
        suggestionsList.add("Game of Thrones Season 6");
        suggestionsList.add("The Walking Dead Season 4");
        suggestionsList.add("Geostorm");
        suggestionsList.add("Inception");
        suggestionsList.add("Jurassic World: Fallen Kingdom");
        suggestionsList.add("Deadpool 2");
        suggestionsList.add("How I Met Your Mother");
        suggestionsList.add("Tron: Legacy");
        return suggestionsList;
    }

    @Override
    protected void onStart() {
        super.onStart();
        EventBus.getDefault().register(this);
    }

    @Override
    protected void onStop() {
        super.onStop();
        EventBus.getDefault().unregister(this);
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void displayText(EventDisplayText eventDisplayText) {
        if (eventDisplayText != null) {
            mEdtSearch.setText(eventDisplayText.getDisplayedText().toString());
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void showRecentSearches(EventSearching eventSearching) {
        if (eventSearching != null) {
            mRecentSearchesAdapter.setSearchContent(eventSearching.getSearchContent());
            mEdtSearch.setText(null);
            customSoftKeyboardView.reset();
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void receiveFocusedViews(EventSendFocusedView eventSendFocusedView) {
        if (eventSendFocusedView != null) {
            currentFocusedView = eventSendFocusedView.getCurrentFocusedView();
            nextFocusedView = eventSendFocusedView.getNextFocusedView();
        }
    }


}

activity_main.xml中

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.tv.demo.softkeyboardfortv.MainActivity">

    <EditText
        android:id="@+id/edt_search"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:layout_marginStart="50dp"
        android:layout_marginEnd="50dp"
        android:textColor="#000000"
        android:focusable="false"
        android:textColorHint="#000000"
        android:backgroundTint="#000000"
        android:hint="Search"/>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="10dp">

        <com.tv.demo.softkeyboardfortv.CustomSoftKeyboardView
            android:id="@+id/customKeyboardView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true" />


        <LinearLayout
            android:id="@+id/left_search_list"
            android:layout_alignParentStart="true"
            android:layout_marginStart="53dp"
            android:layout_toStartOf="@id/customKeyboardView"
            android:descendantFocusability="blocksDescendants"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="18sp"
                android:text="RECENT SEARCHES:"
                android:textColor="#000000"/>

            <android.support.v7.widget.RecyclerView
                android:id="@+id/rv_recentSearches"
                android:layout_marginTop="10dp"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>

        </LinearLayout>

    </RelativeLayout>

</LinearLayout>

custom_keyboard_item.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:focusable="true"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <LinearLayout
        android:id="@+id/keyPadsContainer"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/rv_keyPads"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <LinearLayout
            android:id="@+id/bottomRoot"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginStart="10dp"
            android:layout_marginTop="10dp"
            android:orientation="horizontal">

            <TextView
                android:id="@+id/tv_space"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginRight="10dp"
                android:focusable="true"
                android:paddingLeft="5dp"
                android:paddingRight="5dp"
                android:text="SPACE"
                android:textColor="#000000"
                android:textSize="18sp"
                android:textStyle="bold" />

            <TextView
                android:id="@+id/tv_search"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:focusable="true"
                android:paddingLeft="5dp"
                android:paddingRight="5dp"
                android:text="SEARCH"
                android:textColor="#000000"
                android:textSize="18sp"
                android:textStyle="bold" />


        </LinearLayout>


    </LinearLayout>


    <LinearLayout
        android:id="@+id/rightRoot"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:layout_toEndOf="@id/keyPadsContainer"
        android:orientation="vertical">

        <TextView
            android:id="@+id/tv_keyDelete"
            style="@style/RightKeyPads"
            android:focusable="true"
            android:nextFocusDown="@id/tv_keyClear"
            android:text="@string/delete_pad" />

        <TextView
            android:id="@+id/tv_keyClear"
            style="@style/RightKeyPads"
            android:focusable="true"
            android:nextFocusDown="@id/tv_keyNumbers"
            android:text="@string/clear_pad" />

        <TextView
            android:id="@+id/tv_keyNumbers"
            style="@style/RightKeyPads"
            android:focusable="true" />

    </LinearLayout>


</RelativeLayout>

我有一些问题要问:

  1. 在关键垫上: A H O V SPACE 即可。当我按 DPAD_LEFT 时,如何让它专注于RecentSearches RecyclerView的第一项(总是第一项)

  2. 与键盘相同: V W X Y Z - &#39; ,按 DPAD_DOWN 时,始终关注 SPACE < / p>

  3. 当前焦点位于Recent Searches RecyclerView项目(任何索引)时,当我按 DPAD_RIGHT 时,它必须返回到之前的精确聚焦视图(例如:V(当前聚焦)查看) - &gt;按 DPAD_LEFT - &gt;最近搜索的第一个索引RecyclerView项目(当前关注的) - &gt;按 DPAD_DOWN - &gt;第二个项目(dota 2 wtf) (以当前为中心) - &gt;按 DPAD_RIGHT - &gt; V

  4. 我很欣赏我的3个问题。谢谢你的阅读。

0 个答案:

没有答案