android - studio - viewpager not showing fragment
ViewPager dentro de ViewPager (8)
Me gustaría crear una ViewPager (con tres elementos) donde cada una de sus vistas es otra ViewPager (con dos elementos). El usuario luego desliza elementos como este:
ViewPager1[0] ViewPager2[0]
ViewPager1[0] ViewPager2[1]
ViewPager1[1] ViewPager2[0]
ViewPager1[1] ViewPager2[1]
ViewPager1[2] ViewPager2[0]
ViewPager1[2] ViewPager2[1]
¿Cómo sería eso posible?
Acabo de probar este caso, puedes hacerlo sin trabajar extra, debajo está mi demo
@Override
public Object instantiateItem(View collection, int position) {
LayoutInflater inflater = THISCLASSNAME.this.getLayoutInflater();
View v = null;
if(position%2 == 0) {
// viewpager 1 code
int vp1pos = position/2;
v = inlater.inflate(R.layout.somelayout, collection, false);
Button b = (Button)v.findViewById(R.id.somebutton);
b.setText(array1[vp1pos]);
} else {
int vp2pos = (position-1)/2;
v = inlater.inflate(R.layout.somelayout, collection, false);
Button b = (Button)v.findViewById(R.id.somebutton);
b.setText(array2[vp2pos]);
}
((DirectionalViewPager) collection).addView(v, 0);
return v;
}
El xml es simple, ViewPager
externo en mi diseño principal y ViewPager
interno en otro LinearLayout
Busqué mucho tiempo para hacer una ViewPager dentro de otro trabajo de ViewPager y encontré la solución por "Android Noob" aquí. ¡Muchas gracias por eso!
Yo quería compartir mi solución, también. Agregué la posibilidad de cambiar la administración de deslizamiento a la ViewPager circundante una vez que se alcanza el último elemento (el más adecuado) en el ViewPager interno. Para evitar problemas técnicos, también guardo la primera dirección de deslizamiento para el último elemento: es decir, si desliza el dedo hacia la izquierda primero, un deslizamiento hacia la derecha mínimo no restablece el estado de desplazamiento.
public class GalleryViewPager extends ViewPager {
/** the last x position */
private float lastX;
/** if the first swipe was from left to right (->), dont listen to swipes from the right */
private boolean slidingLeft;
/** if the first swipe was from right to left (<-), dont listen to swipes from the left */
private boolean slidingRight;
public GalleryViewPager(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
public GalleryViewPager(final Context context) {
super(context);
}
@Override
public boolean onTouchEvent(final MotionEvent ev) {
final int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
// Disallow parent ViewPager to intercept touch events.
this.getParent().requestDisallowInterceptTouchEvent(true);
// save the current x position
this.lastX = ev.getX();
break;
case MotionEvent.ACTION_UP:
// Allow parent ViewPager to intercept touch events.
this.getParent().requestDisallowInterceptTouchEvent(false);
// save the current x position
this.lastX = ev.getX();
// reset swipe actions
this.slidingLeft = false;
this.slidingRight = false;
break;
case MotionEvent.ACTION_MOVE:
/*
* if this is the first item, scrolling from left to
* right should navigate in the surrounding ViewPager
*/
if (this.getCurrentItem() == 0) {
// swiping from left to right (->)?
if (this.lastX <= ev.getX() && !this.slidingRight) {
// make the parent touch interception active -> parent pager can swipe
this.getParent().requestDisallowInterceptTouchEvent(false);
} else {
/*
* if the first swipe was from right to left, dont listen to swipes
* from left to right. this fixes glitches where the user first swipes
* right, then left and the scrolling state gets reset
*/
this.slidingRight = true;
// save the current x position
this.lastX = ev.getX();
this.getParent().requestDisallowInterceptTouchEvent(true);
}
} else
/*
* if this is the last item, scrolling from right to
* left should navigate in the surrounding ViewPager
*/
if (this.getCurrentItem() == this.getAdapter().getCount() - 1) {
// swiping from right to left (<-)?
if (this.lastX >= ev.getX() && !this.slidingLeft) {
// make the parent touch interception active -> parent pager can swipe
this.getParent().requestDisallowInterceptTouchEvent(false);
} else {
/*
* if the first swipe was from left to right, dont listen to swipes
* from right to left. this fixes glitches where the user first swipes
* left, then right and the scrolling state gets reset
*/
this.slidingLeft = true;
// save the current x position
this.lastX = ev.getX();
this.getParent().requestDisallowInterceptTouchEvent(true);
}
}
break;
}
super.onTouchEvent(ev);
return true;
}
}
¡Espero que esto ayude a alguien en el futuro!
No entiendo por qué no creas un localizador de 1 vista y creas la lógica del elemento instanciado para obtener datos de diferentes fuentes, lo que te haría alcanzar tu objetivo igualmente. No veo un caso en el que necesites 2 viewpagers
Ejemplo
public class InnerViewPager extends ViewPager
{
private int mPrevMoveX;
public InnerViewPager(Context context)
{
super(context);
}
public InnerViewPager(Context context, AttributeSet attrs)
{
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event)
{
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
mPrevMoveX = (int) event.getX();
return super.onTouchEvent(event);
case MotionEvent.ACTION_MOVE:
int distanceX = mPrevMoveX - (int) event.getX();
mPrevMoveX = (int) event.getX();
boolean canScrollLeft = true;
boolean canScrollRight = true;
if(getCurrentItem() == getAdapter().getCount() - 1)
{
canScrollLeft = false;
}
if(getCurrentItem() == 0)
{
canScrollRight = false;
}
if(distanceX > 0)
{
return canScrollRight;
}
else
{
return canScrollLeft;
}
}
return super.onInterceptTouchEvent(event);
}
public boolean onTouchEvent(MotionEvent event)
{
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mPrevMoveX = (int) event.getX();
return super.onTouchEvent(event);
case MotionEvent.ACTION_MOVE:
int distanceX = mPrevMoveX - (int) event.getX();
mPrevMoveX = (int) event.getX();
boolean canScrollLeft = true;
boolean canScrollRight = true;
if(getCurrentItem() == getAdapter().getCount() - 1)
{
canScrollLeft = false;
}
if(getCurrentItem() == 0)
{
canScrollRight = false;
}
if(distanceX > 0)
{
super.onTouchEvent(event);
return canScrollLeft;
}
else
{
super.onTouchEvent(event);
return canScrollRight;
}
}
return super.onTouchEvent(event);
}
}
public class OuterViewPager extends ViewPager
{
private int mPrevMoveX;
public OuterViewPager(Context context)
{
super(context);
init();
}
public OuterViewPager(Context context, AttributeSet attrs)
{
super(context, attrs);
init();
}
private void init()
{
setOnPageChangeListener(new CustomPageChangeListener());
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev)
{
switch (ev.getAction())
{
case MotionEvent.ACTION_DOWN:
mPrevMoveX = (int) ev.getX();
return super.onInterceptTouchEvent(ev);
case MotionEvent.ACTION_MOVE:
/*there you should get currentInnerPager - instance of InnerPager on current page of instance of OuterPager*/
int distanceX = mPrevMoveX - (int) ev.getX();
mPrevMoveX = (int) ev.getX();
boolean canScrollLeft = true;
boolean canScrollRight = true;
if(currentInnerPager.getCurrentItem() == currentInnerPager.getAdapter().getCount() - 1)
{
canScrollLeft = false;
}
if(currentInnerPager.getCurrentItem() == 0)
{
canScrollRight = false;
}
if(distanceX > 0)
{
return !canScrollLeft;
}
else
{
return !canScrollRight;
}
}
return super.onInterceptTouchEvent(ev);
}
}
y en el código:
public class MainActivity extends AppCompatActivity {
public static final String TAG = "TAG";
ViewPager parentPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
initViews();
initData();
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
}
private void initViews() {
parentPager = (ViewPager) findViewById(R.id.parent_pager);
}
private void initData() {
List<ViewPager> pagers = new ArrayList<ViewPager>();
for(int j = 0; j < 3; j++) {
List<LinearLayout> list = new ArrayList<LinearLayout>();
for (int i = 0; i < 5; i++) {
LinearLayout layout = new LinearLayout(this);
TextView textView = new TextView(this);
textView.setText("This is the" + i + "th page in PagerItem" + j);
layout.addView(textView);
textView.setGravity(Gravity.CENTER);
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) textView.getLayoutParams();
params.gravity = Gravity.CENTER;
list.add(layout);
}
MyViewPagerAdapter adapter = new MyViewPagerAdapter(list);
final ViewPager childPager = (ViewPager) LayoutInflater.from(this).inflate(R.layout.child_layout, null).findViewById(R.id.child_pager);
childPager.setAdapter(adapter);
childPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
Log.d(TAG, "onPageScrolled: position: " + position + ", positionOffset: " + positionOffset);
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
pagers.add(childPager);
}
MyParentViewPagerAdapter parentAdapter = new MyParentViewPagerAdapter(pagers);
parentPager.setAdapter(parentAdapter);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
class MyViewPagerAdapter extends PagerAdapter {
private List<LinearLayout> data;
public MyViewPagerAdapter(List<LinearLayout> data) {
this.data = data;
}
@Override
public int getCount() {
return data.size();
}
@Override
public int getItemPosition(Object object) {
return data.indexOf(object);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
LinearLayout linearLayout = data.get(position);
container.addView(linearLayout);
return data.get(position);
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
LinearLayout layout = data.get(position);
container.removeView(layout);
layout = null;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
}
class MyParentViewPagerAdapter extends PagerAdapter {
private List<ViewPager> data;
public MyParentViewPagerAdapter(List<ViewPager> data) {
this.data = data;
}
@Override
public int getCount() {
return data.size();
}
@Override
public int getItemPosition(Object object) {
return data.indexOf(object);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
ViewPager pager = data.get(position);
if(pager.getParent() != null) {
((ViewGroup) pager.getParent()).removeView(pager);
}
container.addView(pager);
return data.get(position);
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
ViewPager pager = data.get(position);
container.removeView(pager);
pager = null;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
}
}
De esta forma tienes prácticamente 2 lógica de viewpagers
, puedes personalizarla más que eso. Solo te estoy dando ideas.
PD: codifiqué esto aquí, así que si hay errores de mayúsculas o errores ortográficos, perdónenme.
Espero que esto ayude, si te vuelves más específico y necesitas más ayuda para agregar un comentario sobre mi respuesta y lo enmendaré
Primero crea una clase ViewPager personalizada de esta manera:
public class CustomViewPager extends ViewPager {
public CustomViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
if(v instanceof ViewPager) {
return true;
}
return super.canScroll(v, checkV, dx, x, y);
}
}
El retorno (booleano) del método canScroll le dirá si el gesto horizontal para cambiar la página de ViewPager debe estar en el borde derecho o izquierdo del fragmento (verdadero) o si funciona para la pantalla de fragmento completo (falso). Si quiere, por ejemplo, que solo su primer fragmento use el borde derecho para pasar al siguiente fragmento porque el primer fragmento tiene otro evento de desplazamiento horizontal, este será el código para anular el método canScroll:
@Override
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
if(v instanceof ViewPager) {
int currentItem = ((ViewPager) v).getCurrentItem();
if((currentItem==0)){
return true;
}
return false;
}
return super.canScroll(v, checkV, dx, x, y);
}
El último paso será usar su clase CustomViewPager en su clase principal:
ViewPager myPager= (CustomViewPager)myContext.findViewById(R.id.myCustomViewPager);
y el xml:
<my.cool.package.name.CustomViewPager
android:id="@+id/myCustomViewPager"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" />
Prueba esto:
public class CustomViewPager extends ViewPager {
private int childId;
public CustomViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (childId > 0) {
ViewPager pager = (ViewPager)findViewById(childId);
if (pager != null) {
pager.requestDisallowInterceptTouchEvent(true);
}
}
return super.onInterceptTouchEvent(event);
}
public void setChildId(int id) {
this.childId = id;
}
}
Resuelvo esta tarea creando dos herederos personalizados de ViewPager. En mi caso, OuterViewPager e InnerViewPager.
ViewPager1[0] ViewPager2[0] = page 0 (position/2) = 0<br/>
ViewPager1[0] ViewPager2[1] = page 1 ((position-1)/2) = 0<br/>
ViewPager1[1] ViewPager2[0] = page 2 (position/2) = 1<br/>
ViewPager1[1] ViewPager2[1] = page 3 ((position-1)/2) = 1<br/>
ViewPager1[2] ViewPager2[0] = page 4 (position/2) = 2<br/>
ViewPager1[2] ViewPager2[1] = page 5 ((position-1)/2) = 2<br/>
El buscapersonas externo comienza a desplazarse hacia la izquierda solo cuando el buscapersonas interno está en la última página. Y viceversa.
Si el viewpager hijo está al final, desplácese al padre
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
if(v != this && v instanceof ViewPager) {
int currentItem = ((ViewPager) v).getCurrentItem();
int countItem = ((ViewPager) v).getAdapter().getCount();
if((currentItem==(countItem-1) && dx<0) || (currentItem==0 && dx>0)){
return false;
}
return true;
}
return super.canScroll(v, checkV, dx, x, y);
}
anular canScroll en el padre ViewPager:
@Override
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
if(v != this && v instanceof ViewPager) {
return true;
}
return super.canScroll(v, checkV, dx, x, y);
}