Android ScrollView 中的 ViewPager - 垂直滚动不起作用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12669725/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
ViewPager inside ScrollView - vertical scroll doesn't work
提问by Genkaku
So, I have this ScrollView
with one child - a LinearLayout
that has two children: a TextView
and a ViewPager
. ViewPager
contains layout with many elements, that's why i need the ability to scroll vertically. Only pages in ViewPager
may be scrolled horizontally (that is: I'd like to swipe horizontally only within the ViewPager
). That one TextView
must not scroll horizontally but should scroll together with my ViewPager
.
所以,我ScrollView
和一个孩子有这个- aLinearLayout
有两个孩子: aTextView
和 a ViewPager
。ViewPager
包含具有许多元素的布局,这就是为什么我需要能够垂直滚动的原因。只有 中的页面ViewPager
可以水平滚动(即:我只想在 内水平滑动ViewPager
)。那个TextView
不能水平滚动,而应该与我的ViewPager
.
Simple? No.
简单的?不。
I've seen extremely similar issues at StackOverflow popping up (here, hereand hereand here). None of the suggested solutions work for me :(
我在 StackOverflow 上看到了非常相似的问题(这里、这里、这里和这里)。没有一个建议的解决方案对我有用:(
What I see is this<- my sweet UI :), However I cannot scroll vertically :(
我看到的是这个<- 我可爱的用户界面 :),但是我不能垂直滚动 :(
Embedding ScrollViews inside ViewPager is not an option - desing of the UI forbids this.
在 ViewPager 中嵌入 ScrollViews 不是一种选择 - UI 的设计禁止这样做。
Maybe it's something with my programmatically filling each page in view pager? Hmmm...
也许这与我以编程方式填充视图寻呼机中的每个页面有关?嗯...
Any suggestions would be appreciated.
任何建议,将不胜感激。
My code:
我的代码:
activity_main.xml:
活动_main.xml:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/scrollView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@android:color/white"
android:fillViewport="true" >
<LinearLayout
android:id="@+id/linearLayoutGeneral"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tvText"
android:layout_width="fill_parent"
android:layout_height="200dp"
android:text="Test text" />
<android.support.v4.view.ViewPager
android:id="@+android:id/viewpager"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
</android.support.v4.view.ViewPager>
</LinearLayout>
</ScrollView>
each page in ViewPager has this layout:
ViewPager 中的每个页面都有这样的布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/layoutData"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
</LinearLayout>
</LinearLayout>
single element's layout in such a page:
在这样的页面中的单个元素的布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="40dp"
android:gravity="center"
android:orientation="vertical"
android:background="@android:color/white" >
<TextView
android:id="@+id/textView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Large Text"
android:background="@android:color/black"
android:textColor="@android:color/white"
android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>
A single page Fragment is also very simple:
单页 Fragment 也很简单:
public class DayFragment extends Fragment {
private static final String TAG = DayFragment.class.getSimpleName();
public String tag;
LinearLayout data;
View mView;
final int ROWS_NUM = 60;
public DayFragment() {
}
/**
* (non-Javadoc)
*
* @see android.support.v4.app.Fragment#onCreateView(android.view.LayoutInflater,
* android.view.ViewGroup, android.os.Bundle)
*/
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (container == null) {
// We have different layouts, and in one of them this
// fragment's containing frame doesn't exist. The fragment
// may still be created from its saved state, but there is
// no reason to try to create its view hierarchy because it
// won't be displayed. Note this is not needed -- we could
// just run the code below, where we would create and return
// the view hierarchy; it would just never be used.
return null;
}
mView = (LinearLayout) inflater.inflate(R.layout.day, container, false);
setUpControls();
generateData();
String text = getArguments().getString("text");
Log.d(TAG, "creating view with text: " + text);
return mView;
}
private void setUpControls() {
data = (LinearLayout) mView.findViewById(R.id.layoutData);
}
private void generateData() {
for (int i = 0; i < ROWS_NUM; i++) {
View v = createRow(i);
data.addView(v);
}
}
private View createRow(int num) {
LayoutInflater inflater = (LayoutInflater) getActivity()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflater.inflate(R.layout.row, null);
TextView tv = (TextView) v.findViewById(R.id.textView);
tv.setText("Data nr: " + num);
return v;
}
public static DayFragment newInstance(String text) {
Log.d(TAG, "newInstance with text: " + text);
DayFragment f = new DayFragment();
f.tag = text;
// Supply text input as an argument.
Bundle args = new Bundle();
args.putString("text", text);
f.setArguments(args);
return f;
}
}
回答by Marius Hilarious
I had the problem that ViewPager
behaved weird and I found out the reason for that it is because sometimes the ScrollView
regains focus and the ViewPager
then loses focus. If you have a ViewPager
in a ScrollView
and you want it always to stay in focus when you touch it and the ScrollView
never getting a focus, setting the requestDisallowInterceptTouchEvent
does that. Did that help?
我遇到了ViewPager
行为怪异的问题,我发现了原因是因为有时ScrollView
重新获得焦点ViewPager
然后失去焦点。如果你有一个ViewPager
aScrollView
并且你希望它在你触摸它时始终保持焦点并且ScrollView
永远不会得到焦点,那么设置就requestDisallowInterceptTouchEvent
可以了。那有帮助吗?
mViewPager= (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(adapter);
mViewPager.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
mViewPager.getParent().requestDisallowInterceptTouchEvent(true);
return false;
}
});
回答by elimirks
Extending on to Marius's answer to allow vertical scrolling on the parent:
扩展到 Marius 的答案以允许在父级上垂直滚动:
I noticed that when you call the 'requestDisallowInterceptTouchEvent' method on the initial scroll, it will block scrolling vertically on the parent view when scrolling vertically on top of the view pager.
我注意到当您在初始滚动时调用 'requestDisallowInterceptTouchEvent' 方法时,它会在视图分页器顶部垂直滚动时阻止父视图上的垂直滚动。
My solution was to only trigger that method after the user started scrolling horizontally for a specified distance (the 'margin' variable).
我的解决方案是仅在用户开始水平滚动指定距离('margin' 变量)后才触发该方法。
mViewPager.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent e) {
// How far the user has to scroll before it locks the parent vertical scrolling.
final int margin = 10;
final int fragmentOffset = v.getScrollX() % v.getWidth();
if (fragmentOffset > margin && fragmentOffset < v.getWidth() - margin) {
mViewPager.getParent().requestDisallowInterceptTouchEvent(true);
}
return false;
}
});
回答by Ravindra Kushwaha
mPager.setOnTouchListener(new View.OnTouchListener() {
int dragthreshold = 30;
int downX;
int downY;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = (int) event.getRawX();
downY = (int) event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
int distanceX = Math.abs((int) event.getRawX() - downX);
int distanceY = Math.abs((int) event.getRawY() - downY);
if (distanceY > distanceX && distanceY > dragthreshold) {
mPager.getParent().requestDisallowInterceptTouchEvent(false);
mScrollView.getParent().requestDisallowInterceptTouchEvent(true);
} else if (distanceX > distanceY && distanceX > dragthreshold) {
mPager.getParent().requestDisallowInterceptTouchEvent(true);
mScrollView.getParent().requestDisallowInterceptTouchEvent(false);
}
break;
case MotionEvent.ACTION_UP:
mScrollView.getParent().requestDisallowInterceptTouchEvent(false);
mPager.getParent().requestDisallowInterceptTouchEvent(false);
break;
}
return false;
}
});
回答by Kaveh Garshasp
I had same problem try my code to, you we should to disable vertical scrolland sent eventto Scrollview :
我有同样的问题尝试我的代码,你应该禁用垂直滚动并将事件发送到 Scrollview :
private int dragThreshold = 10, int downX = 0, int downY = 0;
vPager.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_UP){
downX = (int) event.getRawX();
downY = (int) event.getRawY();
return false;
}else if(event.getAction() == MotionEvent.ACTION_MOVE){
int distanceX = Math.abs((int) event.getRawX() - downX);
int distanceY = Math.abs((int) event.getRawY() - downY);
ExceptionHelpers.dLog("OnTouchListener", "distance X : "+distanceX+" , distance Y : "+distanceY);
if(distanceY > distanceX && distanceY > dragThreshold){
v.getParent().requestDisallowInterceptTouchEvent(false);
return true;
}
}
v.getParent().requestDisallowInterceptTouchEvent(true);
return false;
}
});
Also you can set Min Horizontal Scroll By Add :
您也可以设置 Min Horizontal Scroll By Add :
else {
distanceX > distanceY && distanceX > dragThreshold)
}
And remember, Building workers do -> Try and Try and Try
记住,建筑工人做 -> 尝试和尝试
developers (us) do -> Think And Think and Try
开发人员(我们)做 -> 思考和思考并尝试
Good Lock
好锁
回答by user3024215
Try this
尝试这个
public static class XScrollDetector extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return Math.abs(distanceY) < Math.abs(distanceX);
}
}
and for the viewpager
和viewpager
final GestureDetector mGestureDetector= new GestureDetector(this,new XScrollDetector());
mViewPager.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
mScrollView.requestDisallowInterceptTouchEvent(mGestureDetector.onTouchEvent(event));
return false;
}
});
回答by youngwoon
I've tried a lot of things, but some things haven't worked for me and some are too complicated and have dirty codes.
我尝试了很多东西,但有些东西对我不起作用,有些东西太复杂并且代码很脏。
I solved this ViewPager in ScrollView
problem this way.
you can update the viewPager size in ViewPager.onMeasure()
or ViewPager.OnPageChangeListener()
我是这样解决这个ViewPager in ScrollView
问题的。
您可以在ViewPager.onMeasure()
或更新viewPager大小ViewPager.OnPageChangeListener()
The method onMeasure()
will be called everytime when the ui changes in fragment. But I had a lots of varying ui (e.g. TabButton), I updated the view pager size only when user scroll pages.
onMeasure()
每次 ui 在片段中更改时都会调用该方法。但是我有很多不同的用户界面(例如 TabButton),我仅在用户滚动页面时更新视图寻呼机大小。
mPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// will work when ViewPager shows first fragment.
if (position != currentPosition) {
currentPosition = position;
updateViewPagerSize(position);
}
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
depending on the situations, you might have to give a focus something to make ScrollView works.
根据情况,您可能需要给焦点一些东西才能使 ScrollView 工作。
public void updateViewPagerSize(int position) {
View view = mPager.getChildAt(position);
view.measure(ViewPager.LayoutParams.WRAP_CONTENT, ViewPager.LayoutParams.WRAP_CONTENT);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, view.getMeasuredHeight());
mPager.setLayoutParams(params);
edtText.requestFocus(); //you might have to give a focus something to use scroll.
}
回答by Konsumierer
Horizontal and vertical scrolling in one Activity is normally a problem. The ViewPager handles this very well. I do not know if there is a good solution for your problem. But I would suggest to get rid of the ScrollView and TextView in your main layout.
一个 Activity 中的水平和垂直滚动通常是一个问题。ViewPager 处理得很好。不知道你的问题有没有好的解决办法。但我建议在你的主布局中去掉 ScrollView 和 TextView。
Use the ViewPager as your starting point for your layout and put the vertical ScrollView inside of the ViewPager Fragments.
使用 ViewPager 作为布局的起点,并将垂直 ScrollView 放在 ViewPager Fragments 中。
回答by Nick Snyder
Disallow the ScrollView to intercept touch events. This requires the user to touch outside the ViewPager to scroll up or down.
禁止 ScrollView 拦截触摸事件。这需要用户在 ViewPager 外部触摸以向上或向下滚动。
mScrollView = (ScrollView) findViewById(R.id.scroll_view);
mViewPager= (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(adapter);
mViewPager.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
mScrollView.requestDisallowInterceptTouchEvent(true);
return false;
}
});