1

我在将 Activity 中的浮动操作按钮的行为与其子项协调时遇到问题。

在我的应用程序中,我有一个Activity包含 aViewPager和一个使用以下 library构造的xml定义。包含灵活数量的,每个里面都有一个。FloatingActionMenuViewPagerFragmentsFragmentRecyclerView

单击时,FloatingActionMenu展开为两个按钮 - 一个在 中添加额外的页面/片段,另一个在用户当前所在页面上ViewPager添加额外的行。此功能有效。RecyclerViewViewPager

为了隐藏按钮,我addOnItemTouchListenerRecyclerView我的子片段中使用。然后,在 中OnInterceptTouchEvent,如果滑动手势足够大,我使用自定义Interface将事件传递回宿主Activity,它会执行动画以隐藏或显示按钮。这是我的一些代码:

public class Categories extends ActionBarActivity implements
        View.OnClickListener,
        FloatingButtonInterface{

//...
// Final parameter is for the custom Interface
    mAdapter = new CategoriesViewPagerAdapter(mFragmentManager, allCategoriesCursor, this); 
    mViewPager = (ViewPager) findViewById(R.id.categories_view_pager_pager);
    mViewPager.setAdapter(mAdapter);

    menuOriginalXPos = mFloatingActionsMenu.getX();
    menuOriginalYPos = mFloatingActionsMenu.getY();

//...
// onTouchEvent is the imaginative name for my custom Interface method.
    @Override
    public void onTouchEvent(int callBackID) {
        if (callBackID == FloatingButtonInterface.MOTION_DOWN){
            if (mFloatingActionsMenu.getVisibility() == View.GONE) {
                Animation translate = new TranslateAnimation(
                        menuOriginalXPos, menuOriginalXPos, mViewPager.getHeight(), menuOriginalYPos);
                translate.setDuration(250);
                translate.setInterpolator(new LinearInterpolator());
                mFloatingActionsMenu.startAnimation(translate);
                mFloatingActionsMenu.setEnabled(true);
                mFloatingActionsMenu.setVisibility(View.VISIBLE);
            }
        } else if (callBackID == FloatingButtonInterface.MOTION_UP) {
            if (mFloatingActionsMenu.getVisibility() == View.VISIBLE) {
                Animation translate = new TranslateAnimation(
                        menuOriginalXPos, menuOriginalXPos, menuOriginalYPos, mViewPager.getHeight());
                translate.setDuration(250);
                translate.setInterpolator(new LinearInterpolator());
                mFloatingActionsMenu.startAnimation(translate);
                mFloatingActionsMenu.setEnabled(false);
                mFloatingActionsMenu.setVisibility(View.GONE);
            }
        }
    }

这是我非常直接的界面:

public interface FloatingButtonInterface {

    public static final int MOTION_UP = 4;
    public static final int MOTION_DOWN = MOTION_UP+1;
    public static final int MOTION_NONE = 0;

    public void onTouchEvent(int callBackID);
}

在我的里面ViewPager

public class CategoriesViewPagerAdapter extends FragmentStatePagerAdapter {

private static final String LOG_TAG = "CategoriesViewPagerAd";

private Cursor mCursor;
private FloatingButtonInterface hideMenuInterface;
private FragmentManager mFragmentManager;
private boolean refreshItem = false;

public CategoriesViewPagerAdapter(FragmentManager fm, Cursor data, FloatingButtonInterface hideMenuInterface) {
    super(fm);
    mCursor = data;
    mFragmentManager = fm;
    this.hideMenuInterface = hideMenuInterface;
}

@Override
public Fragment getItem(int i) {
    mCursor.moveToPosition(i);
    int categoryFragmentIdentifier =
            mCursor.getInt(mCursor.getColumnIndex(FilesDatabaseHelper.KEY_ID));
    CategoryFragment frag = CategoryFragment.newInstance(categoryFragmentIdentifier);
    frag.setOnTouchEvent(hideMenuInterface);
    return frag;
}

最后,其中一个ViewPager Fragment

public class CategoryFragment extends Fragment implements
        RecyclerView.OnItemTouchListener,
        View.OnClickListener{
//...
private static final int TOUCH_SLOP=200;
//...
static CategoryFragment newInstance(int categoryIdentifier){
        CategoryFragment frag = new CategoryFragment();
        Bundle bundle = new Bundle();
        bundle.putInt(CATEGORY_ID, categoryIdentifier);
        frag.setArguments(bundle);

        return frag;
    }
//...
@Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        mRecyclerView.addOnItemTouchListener(this);
//...
    @Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
        switch (e.getAction()){
            case MotionEvent.ACTION_DOWN:
                originalFingerPos = e.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                if (e.getY() - originalFingerPos > TOUCH_SLOP){
                    if (hideMenuInterface != null) {
                        hideMenuInterface.onTouchEvent(FloatingButtonInterface.MOTION_DOWN);
                    } else {
                        Log.e(LOG_TAG, "hideMenuInterface is null");
                    }
                } else if (e.getY() + TOUCH_SLOP < originalFingerPos ){
                    if (hideMenuInterface != null) {
                        hideMenuInterface.onTouchEvent(FloatingButtonInterface.MOTION_UP);
                    } else {
                        Log.e(LOG_TAG, "hideMenuInterface is null");
                    }
                }
        }
        return false;
    }

我遇到的主要问题与我在配置更改后用户在屏幕上向上或向下滑动时用于自动隐藏按钮的代码有关。如果我在测试设备上更改屏幕方向,当我尝试通过滑动隐藏按钮时,有些按钮Fragments没有响应,当我检查时LogCat我可以看到hideMenuInterfacenull. 我能做些什么来解决这个问题?为什么它只影响一些片段而不是所有片段?如果我滑动到 ViewPager 中的最后一个片段,然后再次返回,问题就会自行解决 - 可能是因为片段已被重新创建。

感谢您提供的任何见解!我只包含了我认为相关的代码,否则会有页面,但请询问您是否认为还有其他帮助。

4

1 回答 1

1

I found an answer to this issue in the Android Developer docs. Button behaviour is far more reliable after following the instructions on this page.


Edit:

To expand on my previous answer, I applied the information from the documentation in the following way:

I altered CategoryFragment (the fragment that occupies each ViewPager item) by adding an inner interface called FloatingButtonInterface, and assigned a value to a FloatingButtonInterface variable during onAttach():

public class CategoryFragment extends Fragment implements RecyclerView.OnItemTouchListener {
//...
    private static final int TOUCH_SLOP = 200;
    private FloatingButtonInterface floatingButtonInterface;
//...
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        floatingButtonInterface = (FloatingButtonInterface) activity;
    }
//...
    @Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
        switch (e.getAction()) {
            case MotionEvent.ACTION_DOWN:
                originalFingerPos = e.getY();
                return false;
            case MotionEvent.ACTION_MOVE:
                if (e.getY() - originalFingerPos > TOUCH_SLOP) {
                    floatingButtonInterface.onTouchEvent(FloatingButtonInterface.MOTION_DOWN);
                    return false;
                } else if (e.getY() + TOUCH_SLOP < originalFingerPos) {
                    floatingButtonInterace.onTouchEvent(FloatingButtonInterface.MOTION_UP);
                    return false;
                }
                return false;
            }
            return false;
        }
//...
public interface FloatingButtonInterface {

    public static final int MOTION_UP = MOTION_NONE + 4;
    public static final int MOTION_DOWN = MOTION_UP + 1;
    public static final int MOTION_NONE = 0;

    public void onTouchEvent(int callBackId);
}

The only other change is inside the ViewPagerAdapter. As CategoryFragment is responsible for assigning the interface, any code relating to this in the adapter can be removed, so that the adapter now looks like:

public class CategoriesViewPagerAdapter extends FragmentStatePagerAdapter {

private static final String LOG_TAG = "CategoriesViewPagerAd";

private Cursor mCursor;
private FloatingButtonInterface hideMenuInterface;
private FragmentManager mFragmentManager;
private boolean refreshItem = false;

public CategoriesViewPagerAdapter(FragmentManager fm, Cursor data) {
    super(fm);
    mCursor = data;
    mFragmentManager = fm;
}

@Override
public Fragment getItem(int i) {
    mCursor.moveToPosition(i);
    int categoryFragmentIdentifier =
            mCursor.getInt(mCursor.getColumnIndex(FilesDatabaseHelper.KEY_ID));
    CategoryFragment frag = CategoryFragment.newInstance(categoryFragmentIdentifier);
    return frag;
}
于 2015-04-04T11:29:22.173 回答