Android:EditText焦点跳转到ScrollView里面的另一个

标签 android android-edittext scrollview

我使用 ViewPager 有多个水平相邻的 fragment 。每个 fragment 都有一个 ScrollView,其中包含一个包含许多 EditText View 的表格。当我单击一个 EditText 时,它会获得焦点,然后将焦点转移到最左侧 fragment 中的某个其他 EditText。有时焦点切换会立即发生,有时会在我输入 EditText 时发生。通常,最左边 fragment 中最上面的 EditText 会抢走焦点。

单击最左侧 fragment 中的 EditText 时,我没有看到问题,即使它不是最顶部的 fragment 。就像 Android 不喜欢关注不在左边缘的 TextView 一样。这听起来很熟悉吗?

我没有成功地按照 Skip 在 randomly-jumping 中的建议覆盖 ScrollView 中的 findFocus() 方法.附带的源代码很大,但可能对其他人有用...

package com.example.slideViewPager;

import java.util.ArrayList;

import com.example.slideViewPager.R;

import android.content.Context;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;

public class SlideViewPager extends FragmentActivity {
    private static Context g;
    private static ArrayList<String> pages;
    private static int currentItem;    // restore page position after tilt
    private static int[] scrollStateY;
    private static NotesViewFragment[] fragmentArray;
    private static int id;            // to create unique view ids

    @Override
    public void onCreate(Bundle savedInstanceState) {
        g = getApplicationContext();
        setContentView(R.layout.activity_slide_view_pager);
        pages = new ArrayList<String>();
        for (int i = 0; i < 4; ++i)
            pages.add(Integer.toString(i));

        if (savedInstanceState == null) {
            currentItem = 0;
            scrollStateY = new int[pages.size()];    // assume all 0s
            id = 0;
        }
        else {
            currentItem = savedInstanceState.getInt("currentItem");
            scrollStateY = savedInstanceState.getIntArray("scrollStateY");
            id = savedInstanceState.getInt("id");
            System.out.println("Notes onCreate RESTORE: currentItem="+currentItem+"; id="+id);
        }

        fragmentArray = new NotesViewFragment[pages.size()];
        System.out.println("onCreate: start");
        super.onCreate(savedInstanceState);
        ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
        NotesPagerAdapter pagerAdapter = new NotesPagerAdapter(getSupportFragmentManager());
        viewPager.setAdapter(pagerAdapter);
        viewPager.setCurrentItem(currentItem);
        viewPager.setOnPageChangeListener(onPageChangeListener);
        System.out.println("onCreate: done");
    }

    @Override
    public void onSaveInstanceState(Bundle bundle) {
        System.out.println("Notes: onSaveInstanceState: currentItem="+currentItem);
        super.onSaveInstanceState(bundle);
        bundle.putInt("currentItem", currentItem);
        bundle.putIntArray("scrollStateY", scrollStateY);
        bundle.putInt("id", id);
    }

    public void onBackPressed() {
        System.out.println("Notes: onBackPressed: currentItem="+currentItem);
        super.onBackPressed();
    }

    /////////////////////////////////////////////////////////////////
    public static class NotesPagerAdapter extends FragmentPagerAdapter {

        public NotesPagerAdapter(FragmentManager fm) {
            super(fm);
            System.out.println("NotesPagerAdapter: this="+this);
        }

        @Override
        public Fragment getItem(int position) {
            String pageNum = pages.get(position);
            NotesViewFragment notesViewFragment = NotesViewFragment.initialize(pageNum, position);        // create new fragment
            System.out.println("NotesPagerAdapter: getItem: CREATED position:"+position+" = page:"+pageNum+"; fragment="+notesViewFragment);
            return notesViewFragment;
        }

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

        // nothing being done here
        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            System.out.println("NotesPagerAdapter: destroyItem position="+position);
            super.destroyItem(container, position, object);
        }

        @Override
        public float getPageWidth(int position) {
            System.out.println("NotesPagerAdapter: getPageWidth position="+position);
            return (1.0f/2);    // vary # pages/view
        }
    }

    //////////////////////////////////////////////////////
    public static class NotesViewFragment extends Fragment {
        private int position;    // needed to save scrollY into scrollStateY[]
        private String pageNum;    // index
        private ScrollView itemScrollView;

        public NotesViewFragment() {
            super();
            System.out.println("NotesViewFragment: new this:"+this);
        }

        public static NotesViewFragment initialize(String page, int position) {
            NotesViewFragment notesViewFragment = new NotesViewFragment();
            System.out.println("NotesViewFragment: initialize: this:"+notesViewFragment+"; page: "+page+"; position="+position);
            Bundle args = new Bundle();
            args.putString("pageNum", page);
            args.putInt("position", position);
            scrollStateY[position] = 0;        // start at top
            notesViewFragment.setArguments(args);
            return notesViewFragment;
        }

        @Override
        public void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            System.out.println("NotesViewFragment: onSaveInstanceState this:"+this+"; page: "+pageNum+"; scrollView="+itemScrollView);
            // itemScrollView will be null occasionally (attached but not createViewed)
            if (itemScrollView != null)
                scrollStateY[position] = itemScrollView.getScrollY();
            outState.putString("pageNum", pageNum);
        }

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            Bundle args = getArguments();
            if (args != null) {
                pageNum = args.getString("pageNum");
                position = args.getInt("position");
                fragmentArray[position] = this;
                System.out.println("NotesViewFragment: onCreate: this:"+this+"; page: "+pageNum+"; position="+position+"; yPos="+scrollStateY[position]);
            }
            else    // should not happen
                System.out.println("NotesViewFragment: onCreate: NO ARGS !!! this:"+this);            
        }

        public void onDestroyView() {
            super.onDestroyView();
            if (itemScrollView != null)        // could be null if not createViewed
                scrollStateY[position] = itemScrollView.getScrollY();

            System.out.println("NotesViewFragment: onDestroyView: "+pageNum+" this="+this+"; scrollY="+scrollStateY[position]);
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            if (savedInstanceState != null) {    // config change happened
                pageNum = savedInstanceState.getString("pageNum");
                System.out.println("NotesViewFragment: onCreateView: RESTORED "+pageNum+" this="+this+"; yPos="+scrollStateY[position]);
            }
            else
                System.out.println("NotesViewFragment: onCreateView: "+pageNum+"; this="+this);

            // Inflate the layout containing a title and body text.
            ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_screen_slide_page, container, false);
            TableLayout itemNotesTable = (TableLayout) rootView.findViewById(R.id.tableLayoutNotes);
            TextView itemTitle = (TextView) rootView.findViewById(R.id.textViewTitle);
            itemScrollView = (ScrollView) rootView.findViewById(R.id.scroll_form);
            itemTitle.setText("Team "+pageNum);

            for (int i = 0; i < 12; ++i) {
                TableRow tr = new TableRow(g);
                tr.setId(++id);

                ImageView itemThumbnail = new ImageView(g);
                itemThumbnail.setId(++id);
                itemThumbnail.setImageResource(R.drawable.notes);    // set icon
                tr.addView(itemThumbnail);

                LinearLayout ll = new LinearLayout(g);
                ll.setId(++id);
                ll.setOrientation(LinearLayout.VERTICAL);
                String text = " Team "+pageNum;
                ll.addView(makeTextItem(text, false));

                TextView textView;
                if ((id % 2) == 0) {    // make some entries editable
                    textView = new EditText(g);
                    textView.setFocusable(true);
                    textView.setFocusableInTouchMode(true);
                    textView.setImeOptions(EditorInfo.IME_FLAG_NO_ENTER_ACTION);
                    textView.setOnFocusChangeListener(onFocusChangeListener);
                }
                else
                    textView = new TextView(g);

                textView.setId(++id);
                String str = "Line "+i+" is blah blah blah and more blah blah blah";
                textView.setText(str);
                textView.setTextColor(Color.BLACK);
                textView.setTextSize(16);
                textView.setPadding(2, 2,  2,  2);        // start, top, end, bottom
                ll.addView(textView);
                tr.addView(ll);
                itemNotesTable.addView(tr);
                tr.setOnClickListener(noteClicked);        // make everything in table row clickable
            }

            if (scrollStateY[position] != 0) {
                itemScrollView.post(new Runnable() {
                    public void run() {
                        itemScrollView.scrollTo(0, scrollStateY[position]);
                    }
                });
            }
            return rootView;
        }

        // called from fillNotes
        private static TextView makeTextItem(String label, boolean bold) {
            TextView item = new TextView(g);
            item.setId(++id);
            item.setText(label);
            item.setTextColor(Color.BLACK);
            item.setTextSize(16);
            if (bold)
                item.setTypeface(null, Typeface.BOLD);
            return item;
        }
    }

    // listens for horizontal page scrolls
    ViewPager.OnPageChangeListener onPageChangeListener = new ViewPager.SimpleOnPageChangeListener() {
        @Override
        public void onPageSelected(int position) {
            System.out.println("onPageChangeListener: leaving page:"+currentItem+"; for page: "+position);
            currentItem = position;
        }
    };

    static View.OnFocusChangeListener onFocusChangeListener = new View.OnFocusChangeListener() {

        @Override
        public void onFocusChange(View view, boolean hasFocus) {
            System.out.println("onFocusChangeListener: "+hasFocus+"; "+view);
            if (! hasFocus) {
                EditText editText = (EditText) view;
                String text = editText.getText().toString();
                System.out.println("onFocusChangeListener: "+text);
            }
        }
    };

    static OnClickListener noteClicked = new OnClickListener() {
        public void onClick(View tr) {
            for (View parent = tr; parent != null; parent = (View) parent.getParent()) {
                for (NotesViewFragment fragment : fragmentArray)
                    if (fragment != null  &&  fragment.itemScrollView == parent) {
                        System.out.println("noteClicked: page: "+fragment.pageNum);
                        return;
                    }
            }
        }
    };
}

有几个 XML 文件:fragment_screen_slide_page.xml .........

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/content"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/textViewTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:text=""
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <View
        android:id="@+id/separator"
        android:layout_width="fill_parent"
        android:layout_height="1dip"
        android:layout_alignParentRight="true"
        android:layout_marginTop="4dp"
        android:layout_below="@+id/textViewTitle"
        android:background="#888888" />

    <ScrollView
        android:id="@+id/scroll_form"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/separator" >

        <TableLayout
            android:id="@+id/tableLayoutNotes"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:stretchColumns="1"  >
        </TableLayout>
    </ScrollView>
</RelativeLayout>

和activity_slide_view_pager.xml ----------

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    android:descendantFocusability="beforeDescendants"
    android:focusableInTouchMode="true"
    tools:context=".Page" >

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</RelativeLayout>

最佳答案

焦点正在更改到最左边的 fragment ,因为该 fragment 是 ViewPager 的当前项。您可能会尝试使用 setCurrentItem(item) 将当前项目设置为另一个 fragment (当用户单击它时),这样左边的项目就不会窃取焦点。

发生这种情况是因为在 ViewPagerpopulate() 函数结束时,它总是将焦点放在当前项目中的 View 上。您还可以通过复制 ViewPager 源代码并更改此代码以允许位于 屏幕让 child 专注。

改变这个:

if (hasFocus()) {
    View currentFocused = findFocus();
    ItemInfo ii = currentFocused != null ? infoForAnyChild(currentFocused) : null;
    if (ii == null || ii.position != mCurItem) {
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            ii = infoForChild(child);
            if (ii != null && ii.position == mCurItem) {
                if (child.requestFocus(FOCUS_FORWARD)) {
                    break;
                }
            }
        }
    }
}

像这样:

if (hasFocus()) {
    View currentFocused = findFocus();
    ItemInfo ii = currentFocused != null ? infoForAnyChild(currentFocused) : null;
    if (ii == null || !infoIsOnScreen(ii)) {
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            ii = infoForChild(child);
            if (ii != null && infoIsOnScreen(ii)) {
                if (child.requestFocus(FOCUS_FORWARD)) {
                    break;
                }
            }
        }
    }
}

public boolean infoIsOnScreen(ItemInfo info) {
    // Code to determine if the view is on the screen using ii.offset etc.
}

关于Android:EditText焦点跳转到ScrollView里面的另一个,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21240063/

相关文章:

android - ContentObserver - 简直不敢相信我读过的内容

android - 如何使用默认选项复制并全选以编程方式启动 textview 的上下文操作栏?

android - 将 EditText View 动态添加到水平 ScrollView

iphone - AVplayer 2-3 次后未在 ScrollView 中显示

android - 错误 :File 'workspace.xml' is readonly, 但错过 svn :needs-lock property: Android Studio 2. 2.3

android - Google Play 应用内结算 v3 getSkuDetails() 返回缓存结果,即使 IAP 的价格已更改

java - 如何测试 String 是否为 URL 格式?

java - 在 RecyclerView 中滚动后 EditText 丢失内容

menu - SwiftUI - 如何在表单中添加 "letters sections"和字母跳线?

javascript - React Native ScrollView - 如何从另一个子组件按钮滚动到子组件?