だから、私はこれを1つの子を持つScrollView
-LinearLayout
とTextView
の2つの子を持つViewPager
を持っています。 ViewPager
には多くの要素を含むレイアウトが含まれているため、垂直方向にスクロールする機能が必要です。 ViewPager
のページのみを水平方向にスクロールできます(つまり、ViewPager
内でのみ水平方向にスワイプしたい)。そのTextView
は水平方向にスクロールする必要はありませんが、私のViewPager
と一緒にスクロールする必要があります。
簡単?番号。
StackOverflowで非常によく似た問題が発生しました( here 、 here および here および here ))。提案された解決策のどれも私のために機能しません:(
私が見るのは this <-私の甘いUI :)ですが、垂直方向にスクロールできません:(
ViewPager内にScrollViewを埋め込むことはオプションではありません-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;
}
}
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;
}
});
マリウスの答えに拡張して、親の垂直スクロールを許可します。
最初のスクロールで「requestDisallowInterceptTouchEvent」メソッドを呼び出すと、ビューページャーの上で垂直にスクロールすると、親ビューで垂直スクロールがブロックされることに気付きました。
私の解決策は、ユーザーが指定された距離(「マージン」変数)だけ水平方向にスクロールを開始した後にのみ、そのメソッドをトリガーすることでした。
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;
}
});
これを試して
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;
}
});
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;
}
});
同じ問題でコードを試してみましたが、vertical scrollを無効にし、eventを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;
}
});
また、最小水平スクロールを追加で設定できます。
else {
distanceX > distanceY && distanceX > dragThreshold)
}
そして、覚えておいてください、建設労働者は->試してみて試してみてください
開発者(私たち)が行う->考え、考え、試す
良いロック
多くのことを試しましたが、うまくいかなかったり、複雑すぎたり、コードが汚いものもあります。
私はこの_ViewPager in ScrollView
_の問題をこの方法で解決しました。
viewPagerのサイズはViewPager.onMeasure()
またはViewPager.OnPageChangeListener()
で更新できます
メソッドonMeasure()
は、UIがフラグメントで変更されるたびに呼び出されます。しかし、さまざまな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.
}
_