I am working a project on ParallaxViewPager. I have 3 pages. Everything working normal and the background is parallax as supposed to. But when I add parallaxViewPager.setCurrentItem(2); the background does not appear and it gets default android background. Here is the full code:
MainActivity:
package com.example.myapplication3.app;
import android.app.Activity;
import android.app.ActionBar;
import android.app.Fragment;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.os.Build;
import android.widget.RelativeLayout;
import com.andraskindler.parallaxviewpager.ParallaxViewPager;
import java.io.FileNotFoundException;
import java.io.InputStream;
public class MainActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ParallaxViewPager parallaxViewPager = ((ParallaxViewPager) findViewById(R.id.parallaxviewpager));
parallaxViewPager.setOverlapPercentage(0.25f);
parallaxViewPager.setAdapter(new MyPagerAdapter(getSupportFragmentManager()));
parallaxViewPager.setCurrentItem(2);
}
}
PagerAdapter:
package com.example.myapplication3.app;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import java.util.ArrayList;
import java.util.List;
public class MyPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> fragments;
public MyPagerAdapter(FragmentManager fm) {
super(fm);
this.fragments = new ArrayList<Fragment>();
fragments.add(new view1());
fragments.add(new view2());
fragments.add(new view3());
}
#Override
public Fragment getItem(int position) {
return fragments.get(position);
}
#Override
public int getCount() {
return fragments.size();
}
}
View 1,2,3:
package com.example.myapplication3.app;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class view1 extends Fragment { //view2, view3 on the others
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.view1, container, false); //same here view 2,3
return rootView;
}
}
and the layouts are:
MainActivitys' layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
tools:ignore="MergeRootFrame" >
<com.andraskindler.parallaxviewpager.ParallaxViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/parallaxviewpager"
android:layout_width="match_parent"
android:background="#drawable/sanfran"
android:layout_height="match_parent"/>
</RelativeLayout>
View 1,2,3' layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>
Thanks in advance for your time and help.
I had the same problem with this component. It something like a conflict between the canvas and the destination rect so anything is drawn where it should be done.
I made a fork of the original source repository to update it. When setCurrentItem is invoked I check the position and store an adjust value that I use later in the onDraw method.
You can check it at https://github.com/yuraksisa/parallaxviewpager
Here is a modification of the ParallaxViewPager:
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.*;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
#SuppressLint("NewApi")
public class ParallaxViewPager extends ViewPager {
public static final int FIT_WIDTH = 0;
public static final int FIT_HEIGHT = 1;
public static final float OVERLAP_FULL = 1f;
public static final float OVERLAP_HALF = 0.5f;
public static final float OVERLAP_QUARTER = 0.25f;
public Bitmap bitmap;
private Rect source, destination;
private int scaleType;
private Paint paint;
private OnPageChangeListener secondOnPageChangeListener;
public ParallaxViewPager(Context context) {
super(context);
init();
}
public ParallaxViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
source = new Rect();
destination = new Rect();
scaleType = FIT_HEIGHT;
setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
if (bitmap != null) {
if (position == 0) {
source.left = (int) ((getWidth() / 8) * positionOffset);
source.right = getWidth() + source.left;
destination.left = (int) ((getWidth() * positionOffset) - getWidth());
destination.right = (int) (0 + (getWidth() * positionOffset));
} else {
source.left = (int) ((getWidth() / 8) - (getWidth() / 8)
* positionOffset);
source.right = getWidth() + source.left;
destination.left = (int) ((0 - getWidth()
* positionOffset));
destination.right = (int) (getWidth() - (getWidth() * positionOffset));
}
postInvalidate();
}
if (secondOnPageChangeListener != null) {
secondOnPageChangeListener.onPageScrolled(position,
positionOffset, positionOffsetPixels);
}
}
#Override
public void onPageSelected(int position) {
if (secondOnPageChangeListener != null) {
secondOnPageChangeListener.onPageSelected(position);
}
}
#Override
public void onPageScrollStateChanged(int state) {
if (secondOnPageChangeListener != null) {
secondOnPageChangeListener.onPageScrollStateChanged(state);
}
}
});
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
destination.top = 0;
destination.bottom = h;
if (getAdapter() != null && bitmap != null)
calculateParallaxParameters();
}
private void calculateParallaxParameters() {
if (bitmap.getWidth() < getWidth()
&& bitmap.getWidth() < bitmap.getHeight()
&& scaleType == FIT_HEIGHT) {
Log.w(ParallaxViewPager.class.getName(),
"Invalid bitmap bounds for the current device, parallax effect will not work.");
}
source.top = 0;
source.bottom = bitmap.getHeight();
}
/**
* Sets the background from a resource file.
*
* #param resid
*/
#Override
public void setBackgroundResource(int resid) {
bitmap = BitmapFactory.decodeResource(getResources(), resid);
}
/**
* Sets the background from a Drawable.
*
* #param background
*/
#Override
public void setBackground(Drawable background) {
bitmap = ((BitmapDrawable) background).getBitmap();
}
/**
* Deprecated. Sets the background from a Drawable.
*
* #param background
*/
#Override
public void setBackgroundDrawable(Drawable background) {
bitmap = ((BitmapDrawable) background).getBitmap();
}
/**
* Sets the background from a bitmap.
*
* #param bitmap
* #return The ParallaxViewPager object itself.
*/
public ParallaxViewPager setBackground(Bitmap bitmap) {
this.bitmap = bitmap;
return this;
}
public ParallaxViewPager setScaleType(final int scaleType) {
if (scaleType != FIT_WIDTH && scaleType != FIT_HEIGHT)
throw new IllegalArgumentException(
"Illegal argument: scaleType must be FIT_WIDTH or FIT_HEIGHT");
this.scaleType = scaleType;
return this;
}
/**
* Sets the amount of overlapping with the setOverlapPercentage(final float
* percentage) method. This is a number between 0 and 1, the smaller it is,
* the slower is the background scrolling.
*
* #param percentage
* #return The ParallaxViewPager object itself.
*/
public ParallaxViewPager setOverlapPercentage(final float percentage) {
if (percentage <= 0 || percentage >= 1)
throw new IllegalArgumentException(
"Illegal argument: percentage must be between 0 and 1");
return this;
}
/**
* Recalculates the parameters of the parallax effect, useful after changes
* in runtime.
*
* #return The ParallaxViewPager object itself.
*/
public ParallaxViewPager invalidateParallaxParameters() {
calculateParallaxParameters();
return this;
}
#Override
protected void onDraw(Canvas canvas) {
if (bitmap != null) {
canvas.drawBitmap(bitmap, source, destination, paint);
}
}
public void addOnPageChangeListener(OnPageChangeListener listener) {
secondOnPageChangeListener = listener;
}
}
And here is how to use:
viewPager = (ParallaxViewPager)findViewById(R.id.lock_viewpager);
viewPager.setBackgroundDrawable(new BitmapDrawable());
viewPager.setAdapter(new MyViewPagerAdapter());
viewPager.addOnPageChangeListener(this);
viewPager.setCurrentItem(mList.size());
Related
I have tried to implement gradient view via native UI component RN approach (Android only for now). Everything seems fine except one: #ReactProp setters doesn't called and I don't even imagine why :(
Details:
- RN version: 0.60.4
Here is the code (ViewManager, View, RN component):
ViewManager:
package com.bastionpassmobile.splashgradient;
import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
/**
* View manager for splash background gradient view.
*/
public class SplashGradientViewManager extends SimpleViewManager<SplashGradientView> {
public static final String REACT_CLASS = "RCTSplashGradientView";
#Override
public String getName() {
return REACT_CLASS;
}
#Override
protected SplashGradientView createViewInstance(ThemedReactContext reactContext) {
return new SplashGradientView(reactContext);
}
}
View:
package com.bastionpassmobile.splashgradient;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RadialGradient;
import android.graphics.Shader;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.views.view.ReactViewGroup;
/**
* View serves as background gradient for splash screen.
*/
public class SplashGradientView extends ReactViewGroup {
float radius;
int[] colors;
int width;
int height;
public SplashGradientView(Context context) {
super(context);
radius = 0;
colors = new int[0];
width = 0;
height = 0;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (radius > 0) {
RadialGradient radialGradient = new RadialGradient(width / 2, height / 2, radius, colors, null, Shader.TileMode.CLAMP);
Paint paint = new Paint();
paint.setShader(radialGradient);
canvas.drawPaint(paint);
}
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = w;
height = h;
}
/**
* Sets gradient radius.
* #param {SplashGradientView} view
* #param {float} value
*/
#ReactProp(name = "radius")
public void setRadius(SplashGradientView view, float value) {
radius = value;
view.invalidate();
}
/**
* Sets gradient colors.
* #param {SplashGradientView} view
* #param {ReadableArray} value
*/
#ReactProp(name = "colors")
public void setColors(SplashGradientView view, ReadableArray value) {
colors = new int[value.size()];
for (int i = 0; i < value.size(); i++) {
colors[i] = Color.parseColor(value.getString(i));
}
view.invalidate();
}
}
RN component:
import * as React from "react";
import { requireNativeComponent, StyleProp, ViewStyle } from "react-native";
interface CRadialGradientProps {
style?: StyleProp<ViewStyle>;
radius: number;
/**
* Each element of the array should be defined as hex color representation.
*/
colors: string[];
}
const RadialGradientView = requireNativeComponent("RCTSplashGradientView");
/**
* Represents radial gradient view.
*/
export class CRadialGradient extends React.Component<CRadialGradientProps> {
render() {
return (
<RadialGradientView {...this.props}/>
);
}
}
And render of course:
render() {
<CRadialGradient
radius={600}
colors={["#353946", "#1E212C"]}
/>
}
It's my mistake :) #ReactProp setters should be placed in ViewManager implementation instead of View. When I moved methods from View to ViewManager, it works fine.
I have already implemented Carousel Viewpager ...but I m stuck at one point.
There is 10 image item in ArrayList ...First 3 item (0,1,2 position) are showing and we can scroll horizontally one by one
What I want, When I click on first position i.e, 0 it should go position 1 and when I click on position 2, it should come position 1.
How can I achieve this?enter image description here
Method in mainActivity
private void showDrinkList() {
try {
DisplayMetrics metrics = new DisplayMetrics();
Objects.requireNonNull(getActivity()).getWindowManager().getDefaultDisplay().getMetrics(metrics);
int pageMargin = ((metrics.widthPixels / 3) * 2);
pager.setPageMargin(-pageMargin);
CarouselPagerAdapter adapter = new CarouselPagerAdapter(context,this.getChildFragmentManager(), this.getChildFragmentManager(), pager, drinkLists);
pager.setAdapter(adapter);
pager.addOnPageChangeListener(adapter);
if (drinkLists.size() > 1)
pager.setCurrentItem(1);
pager.setOffscreenPageLimit(3);
pager.setHorizontalScrollBarEnabled(true);
} catch (Exception e) {
e.printStackTrace();
} }
Carousel Adapter -
import android.content.Context;
import android.graphics.Interpolator;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.widget.Toast;
import java.lang.reflect.Field;
import java.util.List;
import ae.frink.android.R;
import ae.frink.android.app.customDialog.RedeemDialog;
import ae.frink.android.model.BeanDrinkImage;
import ae.frink.android.utils.FixedSpeedScroller;
import ae.frink.android.utils.ViewPagerCustomDuration;
public class CarouselPagerAdapter extends FragmentPagerAdapter implements ViewPager.OnPageChangeListener {
public final static float BIG_SCALE = 0.8f;
private final static float SMALL_SCALE = 0.4f;
private final static float DIFF_SCALE = BIG_SCALE - SMALL_SCALE;
private FragmentManager context;
private Context c;
private FragmentManager fragmentManager;
private float scale;
public static ViewPager viewPager;
private List<BeanDrinkImage.DrinkList> drinkLists;
private CarouselPagerAdapter adapter;
//private ItemFragment itemFragment;
public CarouselPagerAdapter(Context c, FragmentManager context, FragmentManager fm, ViewPager viewPager,
List<BeanDrinkImage.DrinkList> drinkLists) {
super(fm);
this.fragmentManager = fm;
this.context = context;
this.c = c;
// this.itemFragment = new ItemFragment(drinkLists);
this.viewPager = viewPager;
this.drinkLists = drinkLists;}
#Override
public Fragment getItem(int position) {
// make the first pager bigger than others
try {
if (position == 0) //BarInformationFrag.FIRST_PAGE)
scale = SMALL_SCALE;
else if(position == 1)
scale = BIG_SCALE;
else if(position == 2)
scale = SMALL_SCALE;
else
scale = SMALL_SCALE;
position = position % drinkLists.size();
} catch (Exception e) {
e.printStackTrace();
}
Log.e("drinkSize", "....----" + drinkLists.size());
// ItemFragment itemFragment = new ItemFragment();
return ItemFragment.newInstance(context, position, scale, drinkLists);
}
#Override
public int getCount() {
// int count = 0;
// try {
// count = BarInformationFrag.count * BarInformationFrag.LOOPS;
// } catch (Exception e) {
// // TODO: handle exception
// e.printStackTrace();
// }
// return count;
return drinkLists.size();
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
try {
if (positionOffset >= 0f && positionOffset <= 1f) {
CarouselLinearLayout cur = getRootView(position);
CarouselLinearLayout next = getRootView(position + 1);
cur.setScaleBoth(BIG_SCALE - DIFF_SCALE * positionOffset);
next.setScaleBoth(SMALL_SCALE + DIFF_SCALE * positionOffset);
}
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onPageSelected(int position) {
}
#Override
public void onPageScrollStateChanged(int state) {
}
#SuppressWarnings("ConstantConditions")
private CarouselLinearLayout getRootView(int position) {
return (CarouselLinearLayout) fragmentManager.findFragmentByTag(this.getFragmentTag(position))
.getView().findViewById(R.id.root_container);
}
private String getFragmentTag(int position) {
return "android:switcher:" + viewPager.getId() + ":" + position;
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}
Carousel Linear Layout -
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.widget.LinearLayout;
public class CarouselLinearLayout extends LinearLayout {
private float scale = CarouselPagerAdapter.BIG_SCALE;
// private float scale = .5f;
public CarouselLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CarouselLinearLayout(Context context) {
super(context);
}
public void setScaleBoth(float scale) {
this.scale = scale;
this.invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// The main mechanism to display scale animation, you can customize it as your needs
int w = this.getWidth();
int h = this.getHeight();
canvas.scale(scale, scale, w / 2, h / 2);
}
}
item Fragment -
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.squareup.picasso.Picasso;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import ae.frink.android.R;
import ae.frink.android.app.customDialog.RedeemDialog;
import ae.frink.android.connection.ApiClient;
import ae.frink.android.model.BeanDrinkImage;
import static ae.frink.android.Carousel.CarouselPagerAdapter.viewPager;
public class ItemFragment extends Fragment {
private static final String POSITON = "position";
private static final String SCALE = "scale";
private static final String DRAWABLE_RESOURE = "resource";
private static final String DRINK_LIST = "drinkList";
private List<BeanDrinkImage.DrinkList> dL;
private static final String IMAGE = "image";
public ArrayList<Integer> imageArray;
private Context context;
private List<BeanDrinkImage.DrinkList> drinkLists;
private SharedPreferences sharedPreferences;
private int screenWidth;
private int screenHeight;
/* private int[] imageArray = new int[]{R.drawable.cocktail_lime_gin_fizz_1, R.drawable.cocktail_lime_gin_fizz_1,
R.drawable.cocktail_lime_gin_fizz_1, R.drawable.cocktail_lime_gin_fizz_1, R.drawable.cocktail_lime_gin_fizz_1,
R.drawable.cocktail_lime_gin_fizz_1, R.drawable.cocktail_lime_gin_fizz_1, R.drawable.cocktail_lime_gin_fizz_1,
R.drawable.cocktail_lime_gin_fizz_1, R.drawable.cocktail_lime_gin_fizz_1};
*/
public ItemFragment() {
}
/*
#SuppressLint("ValidFragment")
public ItemFragment(List<BeanDrinkImage.DrinkList> drinkLists) {
this.drinkLists = drinkLists;
}
*/
public static Fragment newInstance(FragmentManager context, int pos, float scale, List<BeanDrinkImage.DrinkList> dL) {
ItemFragment fr = new ItemFragment();
Bundle b = new Bundle();
b.putInt(POSITON, pos);
b.putFloat(SCALE, scale);
b.putParcelableArrayList(DRINK_LIST, (ArrayList) dL);
//drinkLists=dL;
// this.context = context;
// this.dL = dL;
// b.putIntegerArrayList(IMAGE, imageArray);
Log.e("drinkSize", "....+++"+dL.size());
fr.setArguments(b);
return fr;//frFragment.instantiate(context, ItemFragment.class.getName(), b);
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWidthAndHeight();
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
}
#SuppressLint("SetTextI18n")
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (container == null) {
return null;
}
context = getActivity();
final int postion = this.getArguments().getInt(POSITON);
float scale = this.getArguments().getFloat(SCALE);
this.imageArray = this.getArguments().getIntegerArrayList(IMAGE);
drinkLists = (ArrayList) this.getArguments().getParcelableArrayList(DRINK_LIST);
// TODO 21 sep changes
// LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(screenWidth / 3,
// h/4);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(screenWidth / 2,
screenWidth/2);
LinearLayout linearLayout = (LinearLayout) inflater.inflate(R.layout.fragment_image, container, false);
TextView textView = (TextView) linearLayout.findViewById(R.id.text);
CarouselLinearLayout root = (CarouselLinearLayout) linearLayout.findViewById(R.id.root_container);
ImageView imageView = (ImageView) linearLayout.findViewById(R.id.pagerImg);
ImageView starImage = (ImageView) linearLayout.findViewById(R.id.imgStar);
imageView.setLayoutParams(layoutParams);
String imageUrl = "";
try {
Log.e("drinkSize", "...."+drinkLists.size());
if (drinkLists.size() > 0) {
imageUrl = ApiClient.IMAGE_URL + drinkLists.get(postion).getImage();
Picasso.get().load(imageUrl).into(imageView);
Log.e("drinkName", drinkLists.get(postion).getDrinkName());
textView.setText(drinkLists.get(postion).getDrinkName());
if (drinkLists.get(postion).getIs_recomended() == 1) {
starImage.setVisibility(View.VISIBLE);
} else {
starImage.setVisibility(View.INVISIBLE);
}
}
imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (getActivity() != null) {
RedeemDialog redeemDialog = new RedeemDialog(getActivity(), drinkLists, postion);
redeemDialog.setCanceledOnTouchOutside(true);
redeemDialog.show();
// 12-march
/* if (sharedPreferences.getString(CommonVar.IS_SUBSCRIBED, "0").equals("0")) {
Toast.makeText(getContext(), "Please subscribe first", Toast.LENGTH_SHORT).show();
} else {
RedeemDialog redeemDialog = new RedeemDialog(getActivity(), list, postion);
redeemDialog.setCanceledOnTouchOutside(true);
redeemDialog.show();
}*/
}
}
});
root.setScaleBoth(scale);
} catch (Exception e) {
e.printStackTrace();
}
return linearLayout;
}
/**
* Get device screen width and height
*/
private void getWidthAndHeight() {
DisplayMetrics displaymetrics = new DisplayMetrics();
try {
Objects.requireNonNull(getActivity()).getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
screenHeight = displaymetrics.heightPixels;
screenWidth = displaymetrics.widthPixels;
} catch (Exception e) {
e.printStackTrace();
}
}
}
if (position == 0) {
scale = SMALL_SCALE;}
else if(position == 1){
scale = BIG_SCALE;
}
else if(position == 2)
{
scale = SMALL_SCALE;
}
else{
scale = SMALL_SCALE;
}
holder.setIsRecyclable(false);
I want to Implement Interface in which the Screen is divided into two halves vertically and the lower half is partially visible, using Fragments just like in Google Duo application.
I am trying to achieve this thing using Fragment, some how I got succeeded to some extent but the problem is that fragments are not fluid in movement and the second fragment is not partially visible. Here is a piece of code
VertcialViewPager.Java
package com.example.deepdepindersingh.adore.ui;
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
* Created by Deep Depinder Singh on 10/16/2016.
*/
public class VerticalViewPager extends ViewPager {
public VerticalViewPager(Context context) {
super(context);
init();
}
public VerticalViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
// The majority of the magic happens here
setPageTransformer(true, new VerticalPageTransformer());
// The easiest way to get rid of the overscroll drawing that happens on the left and right
setOverScrollMode(OVER_SCROLL_NEVER);
}
private class VerticalPageTransformer implements ViewPager.PageTransformer {
#Override
public void transformPage(View view, float position) {
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 1) { // [-1,1]
view.setAlpha(1);
// Counteract the default slide transition
view.setTranslationX(view.getWidth() * -position);
//set Y position to swipe in from top
float yPosition = position * view.getHeight();
view.setTranslationY(yPosition);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
/**
* Swaps the X and Y coordinates of your touch event.
*/
private MotionEvent swapXY(MotionEvent ev) {
float width = getWidth();
float height = getHeight();
float newX = (ev.getY() / height) * width;
float newY = (ev.getX() / width) * height;
ev.setLocation(newX, newY);
return ev;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev){
boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
swapXY(ev); // return touch coordinates to original reference frame for any child views
return intercepted;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
return super.onTouchEvent(swapXY(ev));
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
boolean wrapHeight = MeasureSpec.getMode(heightMeasureSpec)
== MeasureSpec.AT_MOST;
if(wrapHeight) {
/**
* The first super.onMeasure call made the pager take up all the
* available height. Since we really wanted to wrap it, we need
* to remeasure it. Luckily, after that call the first child is
* now available. So, we take the height from it.
*/
int width = getMeasuredWidth(), height = getMeasuredHeight();
// Use the previously measured width but simplify the calculations
widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
/* If the pager actually has any children, take the first child's
* height and call that our own */
if(getChildCount() > 0) {
View firstChild = getChildAt(0);
/* The child was previously measured with exactly the full height.
* Allow it to wrap this time around. */
firstChild.measure(widthMeasureSpec,
MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
height = firstChild.getMeasuredHeight();
}
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}
MainActivity.java
package com.example.deepdepindersingh.adore.ui.userinterface;
import android.Manifest;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.example.deepdepindersingh.adore.ui.R;
import com.example.deepdepindersingh.adore.ui.userinterface.fragments.ListActivityFragment;
import com.example.deepdepindersingh.adore.ui.userinterface.fragments.MapActivityFragment;
import com.example.deepdepindersingh.adore.ui.userinterface.login.LoginActivity;
import com.example.deepdepindersingh.adore.ui.utils.Constants;
import java.util.HashMap;
public class MainActivity extends BaseActivity implements com.google.android.gms.location.LocationListener{
protected static final String TAG = MainActivity.class.getSimpleName();
private FragmentPagerAdapter adapterViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Intent intent = new Intent(this, LoginActivity.class);
// startActivity(intent);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
VerticalViewPager viewPager = (VerticalViewPager) findViewById(R.id.pager);
viewPager.setOffscreenPageLimit(2);
viewPager.setClipChildren(false);
//viewPager.setPageMargin(getResources().getDimensionPixelOffset(R.dimen.viewpager_margin));
adapterViewPager = new MyPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapterViewPager);
}
public class MyPagerAdapter extends FragmentPagerAdapter {
private final int NUM_ITEMS = 2;
public MyPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
// Returns total number of pages
#Override
public int getCount() {
return NUM_ITEMS;
}
/**
* Returns the proportional width of a given page as a percentage of the
* ViewPager's measured width from (0.f-1.f]
*
* #param position The position of the page requested
* #return Proportional width for the given page position
*/
// Returns the fragment to display for that page
#Override
public Fragment getItem(int position) {
switch (position) {
case 0: // Fragment # 0 - This will show FirstFragment
return MapActivityFragment.newInstance(mPhoneNumber);
case 1: // Fragment # 0 - This will show FirstFragment different title
return ListActivityFragment.newInstance(1, "Page # 2");
default:
return null;
}
}
// Returns the page title for the top indicator
#Override
public CharSequence getPageTitle(int position) {
return "Page " + position;
}
}
}
So please help me in creating this Interface which is fluid and similar to DUO application
I have a Custom ViewPager which act like a Carousel, the thing is I want to be able to show multiple page on one. To do so we have 2 solutions :
Using the margins setPageMargin() method
Or we can use Override the getPageWidth method of the adapter of my ViewPager.
The first solution is working great but I want to be able to precise exactly the percentage of my current page. The thing is with the getPageWidth solution my current page is shifting at the left. It's logical because she only takes 80% of her previous size. So I tried to override the scrollTo function of my custom ViewPager like this :
#Override
public void scrollTo(int x, int y) {
x = (int) (x - (getWidth() - getWidth()*getAdapter().getPageWidth(getCurrentItem()))/2);
super.scrollTo(x, y);
}
It's working but I can't scroll as before, it's just acting really weird, don't go in the good direction, don't follow the finger... Is there any solution which allow me to have a working scroll and a centered current page ?
Here is my adapter :
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import java.util.ArrayList;
public class CarouselAdapter extends FragmentPagerAdapter implements ViewPager.OnPageChangeListener {
private ArrayList<Entity> mData = new ArrayList<>();
private ScaledRelativeLayout cur = null, next = null;
private float scale;
private MainActivity context;
private FragmentManager fragmentManager;
public CarouselAdapter(MainActivity context, FragmentManager fragmentManager, ArrayList<Entity> mData) {
super(fragmentManager);
this.fragmentManager = fragmentManager;
this.context = context;
this.mData = mData;
}
#Override
public float getPageWidth(int position) {
return (0.85f);
}
#Override
public Fragment getItem(int position) {
if (position == MainActivity.FIRST_PAGE) {
scale = MainActivity.BIG_SCALE;
} else {
scale = MainActivity.SMALL_SCALE;
}
position = position % mData.size();
Fragment fragment = CarouselFragment.newInstance(context, mData.get(position), position, scale);
return fragment;
}
#Override
public int getCount() {
return mData.size();
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (positionOffset >= 0f && positionOffset <= 1f) {
cur = getRootView(position);
cur.setScaleBoth(MainActivity.BIG_SCALE - MainActivity.DIFF_SCALE * positionOffset);
if (position < mData.size()-1) {
next = getRootView(position +1);
next.setScaleBoth(MainActivity.SMALL_SCALE + MainActivity.DIFF_SCALE * positionOffset);
}
}
}
#Override
public void onPageSelected(int position) {}
#Override
public void onPageScrollStateChanged(int state) {}
private ScaledRelativeLayout getRootView(int position) {
return (ScaledRelativeLayout) fragmentManager.findFragmentByTag(this.getFragmentTag(position)).getView().findViewById(R.id.rootItem);
}
private String getFragmentTag(int position) {
return "android:switcher:" + context.carousel.getId() + ":" + position;
}
}
More useless but here is my MainActivity :
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;
import java.util.ArrayList;
public class MainActivity extends FragmentActivity {
public static int FIRST_PAGE;
public final static float BIG_SCALE = 1.0f;
public final static float SMALL_SCALE = 0.85f;
public final static float DIFF_SCALE = BIG_SCALE - SMALL_SCALE;
public CarouselViewPager carousel;
private CarouselAdapter carouselAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FIRST_PAGE = mData.size()/2;
carouselAdapter = new CarouselAdapter(this, this.getSupportFragmentManager(), mData);
carousel = (CarouselViewPager) findViewById(R.id.carousel);
carousel.setAdapter(carouselAdapter);
carousel.addOnPageChangeListener(carouselAdapter);
carousel.setCurrentItem(Math.round(FIRST_PAGE));
carousel.setOffscreenPageLimit(3);
carousel.setClipToPadding(false);
carousel.setScrollDurationFactor(2.5f);
}
}
Edit :
root.post(new Runnable() {
#Override
public void run() {
int width = root.getWidth();
Log.w("Post", "Width : " + width + ", newWidth : " + (width * 0.8));
// root.setPadding((int) (width * 0.125), 0, (int) (width * 0.125), 0);
ViewPager.LayoutParams params = (ViewPager.LayoutParams) root.getLayoutParams();
params.width = (int) (width * 0.8);
root.setLayoutParams(params);
root.requestLayout();
root.forceLayout();
root.invalidate();
}
});
Regards
Instead of setPageMargin or getPageWidth You can just set padding to your ViewPager.
<android.support.v4.view.ViewPager
android:id="#+id/main_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:clipToPadding="false" />
Notice the clipToPadding part, it is important to show other pages.
If you want to show your width as x% of the screen, you can do this in Java
mRootView.post(new Runnable() {
#Override
public void run() {
int w = mRootView.getWidth();
mViewPager.setPadding(w * 0.25, 0, w * 0.25, 0);
// 25% padding on either side so pages takes exactly 50% space
}
});
Below is my AppConstant.java
package com.domore.gridviewtutorial.helper;
import java.util.Arrays;
import java.util.List;
/**
* Created by MY WORLD on 11/28/2015.
*/
public class AppContant {
// Number of columns of Grid View
public static final int NUM_OF_COLUMNS = 3;
// Gridview image padding
public static final int GRID_PADDING = 8; // in dp
// SD card image directory
public static final String PHOTO_ALBUM = "MyPhotos";
// supported file formats
public static final List<String> FILE_EXTN = Arrays.asList("jpg", "jpeg",
"png");
}
in this class i set the file extension which i load in my app
Here, is my utils class
package com.domore.gridviewtutorial.helper;
import android.app.AlertDialog;
import android.content.Context;
import android.graphics.Point;
import android.view.Display;
import android.view.WindowManager;
import android.widget.Toast;
import java.io.File;
import java.util.ArrayList;
import java.util.Locale;
/**
* Created by MY WORLD on 11/28/2015.
*/
public class Utils {
private Context context;
public Utils(Context context){
this.context=context;
}
public ArrayList<String> getFilePaths(){
ArrayList<String> filePaths=new ArrayList<String>();
File directory=new File(android.os.Environment.getExternalStorageDirectory()+File.separator+AppContant.PHOTO_ALBUM);
if(directory.isDirectory()){
File[] listFiles=directory.listFiles();
if(listFiles.length > 0 ){
for(int i=0;i<listFiles.length;i++){
String filePath=listFiles[i].getAbsolutePath();
if(IsSupportedFile(filePath)){
filePaths.add(filePath);
}
}
}
else{
Toast.makeText(
context,
AppContant.PHOTO_ALBUM
+ " is empty. Please load some images in it !",
Toast.LENGTH_LONG).show();
}
}
else{
AlertDialog.Builder alert = new AlertDialog.Builder(context);
alert.setTitle("Error!");
alert.setMessage(AppContant.PHOTO_ALBUM
+ " directory path is not valid! Please set the image directory name AppConstant.java class");
alert.setPositiveButton("OK", null);
alert.show();
}
return filePaths;
}
private boolean IsSupportedFile(String filePath) {
String ext = filePath.substring((filePath.lastIndexOf(".") + 1),
filePath.length());
if (AppContant.FILE_EXTN
.contains(ext.toLowerCase(Locale.getDefault())))
return true;
else
return false;
}
public int getScreenWidth() {
int columnWidth;
WindowManager wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
final Point point = new Point();
try {
display.getSize(point);
} catch (java.lang.NoSuchMethodError ignore) { // Older device
point.x = display.getWidth();
point.y = display.getHeight();
}
columnWidth = point.x;
return columnWidth;
}
}
Here is my grid_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/grid_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:numColumns="auto_fit"
android:gravity="center"
android:stretchMode="columnWidth"
android:background="#000000">
</GridView>
i have Adapter class to load images
package com.domore.gridviewtutorial.adapter;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.GridView;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import android.view.View.OnClickListener;
/**
* Created by MY WORLD on 11/28/2015.
*/
public class GridViewImageAdapter extends BaseAdapter {
private Activity activity;
private ArrayList<String> _filePaths=new ArrayList<String>();
private int imageWidth;
public GridViewImageAdapter(Activity activity,ArrayList<String> _filePaths,int imageWidth){
this.activity=activity;
this._filePaths=_filePaths;
this.imageWidth=imageWidth;
}
#Override
public int getCount() {
return this._filePaths.size();
}
#Override
public Object getItem(int position) {
return this._filePaths.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if(convertView==null){
imageView=new ImageView(this.activity);
}
else{
imageView=(ImageView)convertView;
}
Bitmap image=decodeFile(this._filePaths.get(position),imageWidth,imageWidth);
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setLayoutParams(new GridView.LayoutParams(imageWidth,
imageWidth));
imageView.setImageBitmap(image);
// image view click listener
imageView.setOnClickListener(new OnImageClickListener(position));
return imageView;
}
class OnImageClickListener implements OnClickListener {
int _postion;
// constructor
public OnImageClickListener(int position) {
this._postion = position;
}
#Override
public void onClick(View v) {
// on selecting grid view image
// launch full screen activity
// Intent i = new Intent(activity, FullScreenViewActivity.class);
// i.putExtra("position", _postion);
// activity.startActivity(i);
}
}
/*
* Resizing image size
*/
public static Bitmap decodeFile(String filePath, int WIDTH, int HIGHT) {
try {
File f = new File(filePath);
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f), null, o);
final int REQUIRED_WIDTH = WIDTH;
final int REQUIRED_HIGHT = HIGHT;
int scale = 1;
while (o.outWidth / scale / 2 >= REQUIRED_WIDTH
&& o.outHeight / scale / 2 >= REQUIRED_HIGHT)
scale *= 2;
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
Here is my MainActivity.java
package com.domore.gridviewtutorial;
import android.content.res.Resources;
import android.support.v7.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.util.TypedValue;
import android.view.View;
import android.view.animation.GridLayoutAnimationController;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.GridView;
import com.domore.gridviewtutorial.adapter.GridViewImageAdapter;
import com.domore.gridviewtutorial.helper.AppContant;
import com.domore.gridviewtutorial.helper.Utils;
import java.util.ArrayList;
public class AndroidGridLayoutActivity extends AppCompatActivity {
private Utils utils;
private ArrayList<String> imagePaths = new ArrayList<String>();
private GridViewImageAdapter adapter;
private GridView gridView;
private int columnWidth;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.grid_layout);
GridView gridView=(GridView)findViewById(R.id.grid_view);
utils=new Utils(this);
InitilizeGridLayout();
imagePaths=utils.getFilePaths();
adapter=new GridViewImageAdapter(AndroidGridLayoutActivity.this,imagePaths,columnWidth);
gridView.setAdapter(adapter);
}
private void InitilizeGridLayout() {
Resources r = getResources();
float padding = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
AppContant.GRID_PADDING, r.getDisplayMetrics());
columnWidth = (int) ((utils.getScreenWidth() - ((AppContant.NUM_OF_COLUMNS + 1) * padding)) / AppContant.NUM_OF_COLUMNS);
gridView.setNumColumns(AppContant.NUM_OF_COLUMNS);
gridView.setColumnWidth(columnWidth);
gridView.setStretchMode(GridView.NO_STRETCH);
gridView.setPadding((int) padding, (int) padding, (int) padding,
(int) padding);
gridView.setHorizontalSpacing((int) padding);
gridView.setVerticalSpacing((int) padding);
}
}
I got error in mainActivity.java
here is my error
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.GridView.setNumColumns(int)' on a null object reference
at com.domore.gridviewtutorial.AndroidGridLayoutActivity.InitilizeGridLayout(AndroidGridLayoutActivity.java:46)
at com.domore.gridviewtutorial.AndroidGridLayoutActivity.onCreate(AndroidGridLayoutActivity.java:34)
can anyone who help me to solve out this error i cannot able to understand.
Your gridView variable is null because you are recreating the a new variable gridView in your onCreate() method and your's activity's instance gridView variable is never get Initialized.
public class AndroidGridLayoutActivity extends AppCompatActivity {
private Utils utils;
private ArrayList<String> imagePaths = new ArrayList<String>();
private GridViewImageAdapter adapter;
private GridView gridView;
private int columnWidth;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.grid_layout);
// initiated the gridView variable
gridView=(GridView)findViewById(R.id.grid_view);
utils=new Utils(this);
InitilizeGridLayout();
imagePaths=utils.getFilePaths();
adapter=new GridViewImageAdapter(AndroidGridLayoutActivity.this,imagePaths,columnWidth);
gridView.setAdapter(adapter);
}
private void InitilizeGridLayout() {
Resources r = getResources();
float padding = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
AppContant.GRID_PADDING, r.getDisplayMetrics());
columnWidth = (int) ((utils.getScreenWidth() - ((AppContant.NUM_OF_COLUMNS + 1) * padding)) / AppContant.NUM_OF_COLUMNS);
gridView.setNumColumns(AppContant.NUM_OF_COLUMNS);
gridView.setColumnWidth(columnWidth);
gridView.setStretchMode(GridView.NO_STRETCH);
gridView.setPadding((int) padding, (int) padding, (int) padding,
(int) padding);
gridView.setHorizontalSpacing((int) padding);
gridView.setVerticalSpacing((int) padding);
}
}