所以,我有一个ScrollView
有一个孩子 - LinearLayout
有两个孩子:TextView
和ViewPager
。 ViewPager
包含许多元素的布局,这就是为什么我需要能够垂直滚动的原因。只有ViewPager
中的页面可以水平滚动(即:我只想在ViewPager
内水平滑动)。那个TextView
不得水平滚动,而应与我的ViewPager
一起滚动。
简单?否。
我在StackOverflow弹出时看到了极为相似的问题(here,here和here以及here)。 建议的解决方案都不适合我:(
我看到的是this< - 我的甜蜜UI :)但是我不能垂直滚动:(
在ViewPager中嵌入ScrollViews不是一个选项 - UI的设计禁止这样做。
也许这是我用编程方式填充查看分页器中的每个页面的东西?嗯...
任何建议都将不胜感激。
我的代码:
activity_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>
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>
在这样的页面中单个元素的布局:
<?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>
单页片段也非常简单:
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;
}
}
答案 0 :(得分:28)
我遇到ViewPager
表现得很奇怪的问题,我发现原因是因为有时ScrollView
重新获得焦点而ViewPager
失去焦点。如果ViewPager
中有ScrollView
,并且您希望它在触摸它时始终保持清晰并且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;
}
});
答案 1 :(得分:11)
延伸到Marius的答案,允许父母垂直滚动:
我注意到当你在初始滚动时调用'requestDisallowInterceptTouchEvent'方法时,它会在视图寻呼机顶部垂直滚动时阻止在父视图上垂直滚动。
我的解决方案是在用户开始水平滚动指定距离('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;
}
});
答案 2 :(得分:1)
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;
}
});
答案 3 :(得分:1)
我有同样的问题 尝试使用我的代码,我们应该停用垂直滚动并将事件发送到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;
}
});
您还可以设置Min Horizontal Scroll By Add:
else {
distanceX > distanceY && distanceX > dragThreshold)
}
请记住,建筑工人会这样做 - &gt;尝试并尝试尝试
开发人员(我们)做 - &gt;思考,思考并尝试
Good Lock
答案 4 :(得分:1)
试试这个
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);
}
}
和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;
}
});
答案 5 :(得分:0)
我已经尝试了很多东西,但是有些东西对我来说没有用,有些东西太复杂了,代码很脏。
我以这种方式解决了ViewPager in ScrollView
这个问题。
您可以在ViewPager.onMeasure()
或ViewPager.OnPageChangeListener()
每次ui片段更改时,都会调用方法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) {
}
});
根据情况,您可能需要集中精力使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.
}
答案 6 :(得分:-1)
一个Activity中的水平和垂直滚动通常是个问题。 ViewPager可以很好地处理这个问题。我不知道你的问题是否有一个好的解决方案。但我建议摆脱主要布局中的ScrollView和TextView。
使用ViewPager作为布局的起点,并将垂直ScrollView放在ViewPager碎片中。
答案 7 :(得分:-1)
禁止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;
}
});