PageViewer内部的GridView具有滞后滚动功能

时间:2018-02-11 07:41:35

标签: android gridview android-viewpager android-gridview

我在GridView内实现了PageViewer,但滚动并不像应该的那样顺利。 GridView内的观点是拦截的。

这让我发疯,我已经尝试了所有的东西,虽然有一件事情起作用,但最终并不是一个好的解决方案。首先是我的代码。

apps_grid.xml

<?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:orientation="vertical">
    <GridView
        android:id="@+id/appGrid"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/ic_launcher_background"
        android:horizontalSpacing="4dp"
        android:numColumns="4"
        android:paddingTop="10dp"
        android:stretchMode="columnWidth"
        android:verticalSpacing="15dp"/>
</LinearLayout>

app_item.xml

<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="vertical">

    <ImageView
        android:id="@+id/icon"
        android:layout_width="54dp"
        android:layout_height="54dp"
        android:layout_gravity="center_horizontal"
        android:src="@mipmap/ic_launcher" />

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="5dp"
        android:ellipsize="end"
        android:gravity="center"
        android:paddingEnd="15dp"
        android:paddingStart="15dp"
        android:singleLine="true"
        android:text="title"
        android:textColor="@android:color/white"
        android:textSize="14sp" />

</LinearLayout>

activity_main.xml中

<android.support.v4.view.ViewPager
    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:id="@+id/viewpager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginTop="45dp"
    android:fillViewport="true"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    />

AppModel.java

public class AppModel {

    private String label;
    private String pkg;
    private Drawable mIcon;

    public AppModel(String name, String pkg, Drawable icon) {
        this.label = name;
        this.pkg = pkg;
        this.mIcon = icon;
    }

    public AppModel(String name) {
        this.label = name;
    }

    public String getLabel() {
        return this.label;
    }

    public String getPkg() {
        return this.pkg;
    }

    public Drawable getIcon() {
        return mIcon;
    }
}

AppListAdapter.java

public class AppListAdapter extends BaseAdapter {

    private ArrayList<AppModel> apps;
    private LayoutInflater layoutInflater;

    public AppListAdapter(Context context, ArrayList<AppModel> apps) {
        this.apps = apps;
        this.layoutInflater = LayoutInflater.from(context);
    }

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

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

    @Override
    public Object getItem(int position) {
        AppModel app = apps.get(position);
        if(app == null) {
            return null;
        }

        return app;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        AppModel app = apps.get(position);

        if (convertView == null) {
            convertView = layoutInflater.inflate(R.layout.app_item, null);
        }

        if(app == null) {
            return convertView;
        }

        ((TextView)convertView.findViewById(R.id.text)).setText(app.getLabel());

        return convertView;
    }
}

TestPagerAdapter.java

public class TestPagerAdapter extends PagerAdapter {

    private Context mContext;
    private LayoutInflater inflater;
    private ArrayList<AppModel> apps;
    private int perPage = 12;

    public TestPagerAdapter(Context context) {
        this.mContext = context;
        this.inflater = LayoutInflater.from(context);
    }

    @Override
    public Object instantiateItem(ViewGroup parent, int position) {
        ViewGroup layout = (ViewGroup) inflater.inflate(R.layout.apps_grid, parent, false);

        ArrayList<AppModel> pageApps = getAppsForPage(position);

        if(pageApps == null) {
            return layout;
        }

        final GridView appGrid = (GridView) layout.findViewById(R.id.appGrid);
        final AppListAdapter gridAdapter = new AppListAdapter(mContext, pageApps);
        appGrid.setVerticalScrollBarEnabled(false);
        appGrid.setAdapter(gridAdapter);
        parent.addView(layout);

        return layout;
    }

    @Override
    public void destroyItem(ViewGroup parent, int position, Object view) {
        parent.removeView((View) view);
    }

    @Override
    public int getCount() {
        if(apps != null) {
            return (int) Math.ceil((double) apps.size() / perPage);
        } else {
            return 0;
        }
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }

    public void setData(ArrayList<AppModel> data) {
        if(data != null) {
            this.apps = data;
        }
    }

    public ArrayList<AppModel> getAppsForPage(int page) {
        if(apps == null) {
            return null;
        }

        int size = apps.size();
        int offset = getOffset(page);

        ArrayList<AppModel> pageApps = new ArrayList<AppModel>(size);

        for(int i = 0; i < perPage; i++) {
            if(offset+i < size) {
                pageApps.add(apps.get(offset+i));
            }
        }

        return pageApps;
    }

    public int getOffset(int page) {
        return perPage*page;
    }

}

MainActivity.java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
    TestPagerAdapter mPAdapter = new TestPagerAdapter(this);
    viewPager.setAdapter(mPAdapter);

    ArrayList<AppModel> items = new ArrayList<AppModel>(20);

    for(int i=0;i<20;i++) {
        AppModel app = new AppModel(""+i);
        items.add(app);
    }
    mPAdapter.setData(items);
    mPAdapter.notifyDataSetChanged();
}

所以,这是我尝试过的: 我将GridView替换为RecyclerView。 在EVERY View

上添加了所有这些属性
android:clickable="false"
android:contextClickable="false"
android:defaultFocusHighlightEnabled="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:focusedByDefault="false"
android:isScrollContainer="false"
android:longClickable="false"
android:nestedScrollingEnabled="false"
android:overScrollMode="never"
android:touchscreenBlocksFocus="false"

覆盖GridView上的OnTouchListener(和许多其他内容)并返回true。 可能还尝试了一些我现在记不住的其他事情了。

唯一可行的是android:filterTouchesWhenObscured="true"上的GridView属性设置,而其他一些应用程序视图位于顶部(因此满足条件“WhenObscured”) 当我尝试这个时,ViewPager开始滚动非常顺利,在其他情况下它有时不会滚动(可能在GridView拦截时)。

请注意,最终GridView内的项目必须是可点击的。

更新

https://github.com/mpa4hu/GridViewPager这是项目的github链接,用类似于这张图片的手势模拟向前和向后滚动的问题

gesture

4 个答案:

答案 0 :(得分:4)

Recycler视图回收视图,并且在需要之前不会重新创建视图。它只是重新绑定视图。

RecyclerView是作为ListView改进创建的,所以是的,您可以使用ListView控件创建附加列表,但使用RecyclerView更容易:

在向上/向下滚动时重用单元格 - 这可以通过在listView适配器中实现View Holder来实现,但这是可选的,而在RecycleView中它是编写适配器的默认方式。

将列表与其容器分离 - 因此您可以在运行时轻松地将列表项放在不同的容器中(linearLayout, gridLayout )并设置 LayoutManager

示例:

mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
//or
mRecyclerView.setLayoutManager(new GridLayoutManager(this, 2));//number 
of columns in a grid layout

有关RecyclerView的更多信息,但我认为这些是主要的。

因此,总而言之,RecyclerView是一种更灵活的控件,用于处理&#34;列出数据&#34;遵循关注点的模式,并为自己留下一个任务 - 回收物品。

您可以在此处参考其优势:RecyclerView over ListView

答案 1 :(得分:2)

由于 appabarScrollingBehaviour ,gridView的滚动滞后... 所以你有禁用你的gridView 的嵌套滚动行为,这样做......只需添加..

<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.0.2</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build>

在你的情况下使用你的gridView ...

(在此处添加Android支持v4库23.1或+)

这些将有希望允许你的GridView  你顺利滚动......

快乐编码:)

修改

  

您也可以尝试ViewCompat.setNestedScrollingEnabled(listView/gridview,false);到您的gridView布局..在xml ..这可能会有所帮助..

答案 2 :(得分:1)

 **I make a change  with recyclerView with gridViewLayoutManager. please see the new change.**
    public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        RecyclerView recyclerView = findViewById(R.id.rvView);

        RecyclerGridView recyclerGridView = new RecyclerGridView(this);
        recyclerView.setLayoutManager(new GridLayoutManager(this, 4, GridLayoutManager.HORIZONTAL, false));
        recyclerView.setAdapter(recyclerGridView);

        ArrayList<AppModel> items = new ArrayList<AppModel>(70);

        for (int i = 0; i < 70; i++) {
            AppModel app = new AppModel("" + i);
            items.add(app);
        }
        recyclerGridView.setData(items);
        recyclerGridView.notifyDataSetChanged();
    }
}


public class RecyclerGridView extends RecyclerView.Adapter<RecyclerGridView.ViewHolder> {

    Context context;
    private ArrayList<AppModel> apps;

    public RecyclerGridView(Context context) {
        this.context = context;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View convertView = LayoutInflater.from(context).inflate(R.layout.app_item, null);
        return new ViewHolder(convertView);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        holder.textView.setText(apps.get(position).getLabel());
    }

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

    public void setData(ArrayList<AppModel> items) {
        this.apps=items;

    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        TextView textView;

        public ViewHolder(View itemView) {
            super(itemView);
            textView = itemView.findViewById(R.id.text);
        }
    }
}




  <?xml version="1.0" encoding="utf-8"?>

<android.support.constraint.ConstraintLayout 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"
    tools:context="com.test.apps.gridviewpager.MainActivity">

    <android.support.v4.view.ViewPager
        android:visibility="gone"
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="350dp"
        />

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

</android.support.constraint.ConstraintLayout>

这是3个文件,可根据您的要求更改网格。它没关系,工作正常,所以我将代码拉到你的分支。

答案 3 :(得分:1)

我有这个银弹子类来解决我自己的嵌套滚动问题:

class NonScrollableRecyclerView : RecyclerView {

    constructor(context: Context) : super(context)
    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)

    override fun onInterceptTouchEvent(event: MotionEvent): Boolean = false
    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent): Boolean = false
}

因此,您可以创建一个自定义不可滚动的GridView,并使用它代替常规的GridView:

class NonScrollableGridView : GridView {

    constructor(context: Context) : super(context)
    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)

    override fun onInterceptTouchEvent(event: MotionEvent): Boolean = false
    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent): Boolean = false
}