ScrollView里面的ScrollView
我知道Google的人要求我们不要将Scrollable视图放在另一个Scrollable视图中,但是有没有官方声明指示我们不这样做?
这足够接近了吗?
你不应该使用一个ListView的HorizontalScrollView,因为ListView负责自己的滚动。 最重要的是,这样做会损害ListView中处理大型列表的所有重要优化,因为它有效地强制ListView显示其整个项目列表,以填充由HorizontalScrollView提供的无限容器。
http://developer.android.com/reference/android/widget/HorizontalScrollView.html
更新:
既然你可能被迫使用二维滚动视图,你可以考虑使用这个: 互联网归档 blog.gorges.us/2010/06/android-two-dimensional-scrollview/
我没有使用这个,但它可能是一个合理的方法。
试试这个
注意:这里parentScrollView
表示外部ScrollView和childScrollView
意味着childScrollView
ScrollView
parentScrollView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.v(TAG, "PARENT TOUCH"); findViewById(R.id.child_scroll).getParent() .requestDisallowInterceptTouchEvent(false); return false; } }); childScrollView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.v(TAG, "CHILD TOUCH"); // Disallow the touch request for parent scroll on touch of child view v.getParent().requestDisallowInterceptTouchEvent(true); return false; } });
Atul Bhardwaj上面的答案是正确的做法。 但是,如果有人需要将其应用于父控制较less的ScrollView,我认为这足够灵活,而且应该是它应该工作的方式:
private void makeMyScrollSmart() { myScroll.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View __v, MotionEvent __event) { if (__event.getAction() == MotionEvent.ACTION_DOWN) { // Disallow the touch request for parent scroll on touch of child view requestDisallowParentInterceptTouchEvent(__v, true); } else if (__event.getAction() == MotionEvent.ACTION_UP || __event.getAction() == MotionEvent.ACTION_CANCEL) { // Re-allows parent events requestDisallowParentInterceptTouchEvent(__v, false); } return false; } }); } private void requestDisallowParentInterceptTouchEvent(View __v, Boolean __disallowIntercept) { while (__v.getParent() != null && __v.getParent() instanceof View) { if (__v.getParent() instanceof ScrollView) { __v.getParent().requestDisallowInterceptTouchEvent(__disallowIntercept); } __v = (View) __v.getParent(); } }
该function的作用是在myScroll
中添加一个触摸监听器,当触摸开始在孩子中时禁用父母的触摸拦截,然后在触摸实际结束时将其启用。 您不需要对父ScrollView
的引用,它不必是直接的父对象……它将显示列表直到find它。
在我看来,两全其美。
childScrollView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: // Disallow ScrollView to intercept touch events. v.getParent().requestDisallowInterceptTouchEvent(true); break; case MotionEvent.ACTION_UP: // Allow ScrollView to intercept touch events. v.getParent().requestDisallowInterceptTouchEvent(false); break; } return false; } });
v.getParent()=父scrollView。
这是一个可能的解决scheme。 当到达孩子ScrollView的结尾时,它将控件传递给父ScrollView进行滚动。 它可以在ScrollView中使用ScrollView和ListView。
第1步 – 设置父级的OnTouchListener
parentScroll.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { v.getParent().requestDisallowInterceptTouchEvent(false); return false; } });
第2步 – 设置儿童的OnTouchListener(ScrollView或ListView)
aChildScrollView.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { v.getParent().requestDisallowInterceptTouchEvent(shouldRequestDisallowIntercept((ViewGroup) v, event)); return false; } }); aListView.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { v.getParent().requestDisallowInterceptTouchEvent(shouldRequestDisallowIntercept((ViewGroup) v, event)); return false; } });
第3步 – 这里是正确function所需的魔术方法
protected boolean shouldRequestDisallowIntercept(ViewGroup scrollView, MotionEvent event) { boolean disallowIntercept = true; float yOffset = getYOffset(event); if (scrollView instanceof ListView) { ListView listView = (ListView) scrollView; if (yOffset < 0 && listView.getFirstVisiblePosition() == 0 && listView.getChildAt(0).getTop() >= 0) { disallowIntercept = false; } else if (yOffset > 0 && listView.getLastVisiblePosition() == listView.getAdapter().getCount() - 1 && listView.getChildAt(listView.getChildCount() - 1).getBottom() <= listView.getHeight()) { disallowIntercept = false; } } else { float scrollY = scrollView.getScrollY(); disallowIntercept = !((scrollY == 0 && yOffset < 0) || (scrollView.getHeight() + scrollY == scrollView.getChildAt(0).getHeight() && yOffset >= 0)); } return disallowIntercept; } protected float getYOffset(MotionEvent ev) { final int historySize = ev.getHistorySize(); final int pointerCount = ev.getPointerCount(); if (historySize > 0 && pointerCount > 0) { float lastYOffset = ev.getHistoricalY(pointerCount - 1, historySize - 1); float currentYOffset = ev.getY(pointerCount - 1); float dY = lastYOffset - currentYOffset; return dY; } return 0; }
有没有他们的正式声明指示我们不这样做?
我认为虽然我似乎无法在笔记中find它。 我知道我在尝试在列表活动中使用滚动视图时发现了这样的声明。 我认为在Android UI系统处理嵌套的可滚动事件的方式中,实际上有一个逻辑焦点“bug”,可能应该更好地检测并传递给开发人员。 但我的build议是…
最后,为了用户的目的,最好考虑单个可滚动的视图。 这就像在HTML页面的滚动条内部有滚动条; 它可能是合法的,但它是一个可怕的用户体验。
其实,有一个关于它的官方声明,在一个叫做“ ListView的世界 ” 的很老的video上 。 他们说不要把任何可滚动的视图放在另一个视图里(当两者都在同一个方向)。
不过,现在我们有了一个新的观点,可以让两个视图同时滚动,可能会显示一个很酷的效果:
https://developer.android.com/reference/android/support/v4/widget/NestedScrollView.html
我没有find任何这方面的例子,所以我写的只是猜测它的作用和用途。
我find了一个很好的解决scheme。 请使用此代码。
parentScrollView.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { Utils.showLog("PARENT TOUCH"); findViewById(R.id.activity_mesh_child_scrollView).getParent().requestDisallowInterceptTouchEvent(false); return false; } }); childScrollView.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { Utils.showLog("CHILD TOUCH"); // Disallow the touch request for parent scroll on touch of child view v.getParent().requestDisallowInterceptTouchEvent(true); return false; } });
这一定会奏效。 请尝试让我知道如果不工作。
你可以把ScrollView放在另一个ScrollView中。 只需扩展子ScrollView来覆盖onTouchEvent方法。 像这样
import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; public class ChildScrollView extends android.widget.ScrollView { private int parent_id; public ChildScrollView(Context context) { super(context); } public ChildScrollView(Context context, AttributeSet attrs) { super(context, attrs); } public ChildScrollView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public boolean onTouchEvent(MotionEvent event){ requestDisallowInterceptTouchEvent(true); return super.onTouchEvent(event); } }
在这里,我已经创build了一个ScrollView中的ScrollView相关的示例项目。 一个视图是可滚动的两种方式。 一探究竟 :-
MainActivity.java –
package com.example.dev_task_193_scrollview; import com.example.dev_task_196_scrollview.R; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.MotionEvent; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.HorizontalScrollView; import android.widget.ImageView; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.ScrollView; import android.widget.Toast; public class MainActivity extends Activity implements View.OnClickListener{ ImageView imageView1,imageView2,imageView3,IVimage1,IVimage2,IVimage3,IVimage4,IVimage5,IVimage6; ListView listView1,listView2; HorizontalScrollView horizontalScrollView1,horizontalScrollView2; ScrollView parentScrollView, scrollView1; RelativeLayout relativeLayout1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); String[] values = new String[] { "Android", "iPhone", "WindowsMobile", "Blackberry", "WebOS", "Ubuntu", "Windows7", "Max OS X", "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X", "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X", "Linux", "OS/2", "Android", "iPhone", "WindowsMobileWindowsMobileWindowsMobileWindowsMobile" }; relativeLayout1 = (RelativeLayout) findViewById(R.id.relativeLayout1); imageView1 = (ImageView) findViewById(R.id.imageView1); imageView1.setBackgroundResource(R.drawable.info); imageView2 = (ImageView) findViewById(R.id.imageView2); imageView2.setBackgroundResource(R.drawable.info); imageView3 = (ImageView) findViewById(R.id.imageView3); imageView3.setBackgroundResource(R.drawable.info); listView1 = (ListView) findViewById(R.id.listView1); ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.list_item, values); listView1.setAdapter(adapter); listView2 = (ListView) findViewById(R.id.listView2); ArrayAdapter<String> adapter1 = new ArrayAdapter<String>(this, R.layout.list_item, values); listView2.setAdapter(adapter1); parentScrollView = (ScrollView) findViewById(R.id.parentScrollView); scrollView1 = (ScrollView) findViewById(R.id.scrollView1); horizontalScrollView1 = (HorizontalScrollView) findViewById(R.id.horizontalScrollView1); horizontalScrollView2 = (HorizontalScrollView) findViewById(R.id.horizontalScrollView2); IVimage1 = (ImageView) findViewById(R.id.IVimage1); IVimage2 = (ImageView) findViewById(R.id.IVimage2); IVimage3 = (ImageView) findViewById(R.id.IVimage3); IVimage4 = (ImageView) findViewById(R.id.IVimage4); IVimage5 = (ImageView) findViewById(R.id.IVimage5); IVimage6 = (ImageView) findViewById(R.id.IVimage6); scrollView1.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { // Disallow the touch request for parent scroll on touch of child view parentScrollView.requestDisallowInterceptTouchEvent(true); return false; } }); horizontalScrollView1.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { // Disallow the touch request for parent scroll on touch of child view parentScrollView.requestDisallowInterceptTouchEvent(true); return false; } }); listView1.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { // Disallow the touch request for parent scroll on touch of child view parentScrollView.requestDisallowInterceptTouchEvent(true); return false; } }); listView1.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Toast.makeText(getApplicationContext(), "Clicked "+parent.getItemAtPosition(position).toString(), Toast.LENGTH_SHORT).show(); } }); listView2.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Toast.makeText(getApplicationContext(), "Clicked "+parent.getItemAtPosition(position).toString(), Toast.LENGTH_SHORT).show(); } }); listView2.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { // Disallow the touch request for parent scroll on touch of child view parentScrollView.requestDisallowInterceptTouchEvent(true); return false; } }); horizontalScrollView2.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { // Disallow the touch request for parent scroll on touch of child view parentScrollView.requestDisallowInterceptTouchEvent(true); return false; } }); /*imageView1.setOnClickListener(this); imageView2.setOnClickListener(this); imageView3.setOnClickListener(this);*/ IVimage1.setOnClickListener(this); IVimage2.setOnClickListener(this); IVimage3.setOnClickListener(this); IVimage4.setOnClickListener(this); IVimage5.setOnClickListener(this); IVimage6.setOnClickListener(this); imageView1.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { // Disallow the touch request for parent scroll on touch of child view parentScrollView.requestDisallowInterceptTouchEvent(true); Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show(); return false; } }); imageView2.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { // Disallow the touch request for parent scroll on touch of child view parentScrollView.requestDisallowInterceptTouchEvent(true); Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show(); return false; } }); imageView3.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { // Disallow the touch request for parent scroll on touch of child view parentScrollView.requestDisallowInterceptTouchEvent(true); Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show(); return false; } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public void onClick(View v) { switch(v.getId()){ case R.id.imageView1: Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show(); break; case R.id.imageView2: Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show(); break; case R.id.imageView3: Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show(); break; case R.id.IVimage1: Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show(); break; case R.id.IVimage2: Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show(); break; case R.id.IVimage3: Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show(); break; case R.id.IVimage4: Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show(); break; case R.id.IVimage5: Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show(); break; case R.id.IVimage6: Toast.makeText(getApplicationContext(), "Clicked "+v.getTag(), Toast.LENGTH_SHORT).show(); break; } // TODO Auto-generated method stub } }
activity_main.xml –
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/parentScrollView" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_marginBottom="5dp" android:layout_marginLeft="5dp" android:layout_marginRight="5dp" android:layout_marginTop="5dp" android:background="@drawable/login_bg" > <RelativeLayout android:id="@+id/relativeLayout1" android:layout_width="match_parent" android:layout_height="wrap_content" > <ScrollView android:id="@+id/scrollView1" android:layout_width="fill_parent" android:layout_height="300dp" > <HorizontalScrollView android:id="@+id/horizontalScrollView1" android:layout_width="match_parent" android:layout_height="300dp" android:fillViewport="false" > <RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:background="@drawable/bg" > <ImageView android:id="@+id/imageView1" android:layout_width="300dp" android:layout_height="400dp" android:tag="imageView1" /> <ImageView android:id="@+id/imageView2" android:layout_width="300dp" android:layout_height="400dp" android:layout_toRightOf="@+id/imageView1" android:tag="imageView2" /> <ImageView android:id="@+id/imageView3" android:layout_width="300dp" android:layout_height="400dp" android:layout_toRightOf="@+id/imageView2" android:tag="imageView3" /> </RelativeLayout> </HorizontalScrollView> </ScrollView> <ListView android:id="@+id/listView1" android:layout_width="500dp" android:layout_height="400dp" android:layout_below="@+id/scrollView1" android:layout_centerHorizontal="true" android:layout_marginTop="5dp" android:background="@drawable/ic_launcherwrweq" > </ListView> <HorizontalScrollView android:id="@+id/horizontalScrollView2" android:layout_width="300dp" android:layout_height="wrap_content" android:layout_below="@+id/listView1" android:layout_centerHorizontal="true" android:layout_gravity="center" android:layout_marginTop="5dp" android:background="@drawable/claim_detail_header_bg" android:fillViewport="true" > <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" > <ImageView android:id="@+id/IVimage1" android:layout_width="125dp" android:layout_height="125dp" android:padding="15dp" android:src="@drawable/a" android:tag="a" > </ImageView> <ImageView android:id="@+id/IVimage2" android:layout_width="125dp" android:layout_height="125dp" android:padding="15dp" android:src="@drawable/b" android:tag="b" > </ImageView> <ImageView android:id="@+id/IVimage3" android:layout_width="125dp" android:layout_height="125dp" android:padding="15dp" android:src="@drawable/c" android:tag="c" > </ImageView> <ImageView android:id="@+id/IVimage4" android:layout_width="125dp" android:layout_height="125dp" android:padding="15dp" android:src="@drawable/g" android:tag="g" > </ImageView> <ImageView android:id="@+id/IVimage5" android:layout_width="125dp" android:layout_height="125dp" android:padding="15dp" android:src="@drawable/e" android:tag="e" > </ImageView> <ImageView android:id="@+id/IVimage6" android:layout_width="125dp" android:layout_height="125dp" android:padding="15dp" android:src="@drawable/f" android:tag="f" > </ImageView> </LinearLayout> </HorizontalScrollView> <ListView android:id="@+id/listView2" android:layout_width="500dp" android:layout_height="400dp" android:layout_below="@+id/horizontalScrollView2" android:layout_centerHorizontal="true" android:layout_marginTop="5dp" android:background="@drawable/ic_launcherwrweq" > </ListView> </RelativeLayout> </ScrollView>
list_item.xml(用于ListView) –
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/text1" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:textSize="25sp" android:maxLines="1" android:singleLine="true" />
Android支持v4库有一个名为NestedScrollView的类。
尝试嵌套滚动视图: http : //ivankocijan.xyz/android-nestedscrollview/
如果有人正在寻找答案,我有一个稍微不同的实现。 我扩展了ScrollView类,并在child中实现了onTouchListener,并在构造函数中将其设置为self。
在onTouchcallback中,如果运动事件对象的指针计数值为2,则返回true,否则返回false。 这样,如果两个手指在屏幕上移动,它会认为它是缩放的捏,否则会认为它是正常的滚动。 我没有要求父母触摸禁用等
@Override public boolean onTouch(View view, MotionEvent motionEvent) { if(motionEvent.getPointerCount() == 2){ mCallbacks.onPinchZoomAction(motionEvent); return true; } return false; }
它不仅是Google说它的坏习惯,它没有太大的意义。 假设你有两个嵌套在一个里面的垂直滚动视图。 当你移动你的手指在滚动视图上,你要移动哪一个,内部还是外部?
你应该重新思考你的用户界面devise,不需要这些,有很多方法来制作一个好的用户界面,而且仍然保持简单。