I have two questions about ViewPager.
I have in my activity 2 ViewPagers, one for each week (of date). For example, one for 14/9/14 - 20/9/14, and the the other one for the next week 21/9/14 - 27/9/14. When I slide the ViewPager to it's next one, it will change each on of the ViewPagers to the next week of itself (21/9/14 - 27/9/14, 28/9/14 - 4/10/14).
When I change the data f the second ViewPager and then slide the first ViewPager to it's next one (and this is the same week like the second view pager data that I changed), it won't show the changes that I made, unless I slide two more times and then return to the changed week (because of the memory of the ViewPager). I tried mPager1.setOffscreenPageLimit(0); , but it didn't helped. What can I do in order to solve that?
I want that when I slide one of my ViewPagers, so the other one will animate itself exactly like my finger is sliding the other ViewPager. Any ideas how to do that?
I hope it helps:
it won't show the changes that I made
use adapter.notifyDataSetChanged(); after you have made changes.
I want that when I slide one of my ViewPagers, so the other one will
animate itself exactly like my finger is sliding the other ViewPager.
Any ideas how to do that?
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager1= (ViewPager) findViewById(R.id.pager1);
viewPager2= (ViewPager) findViewById(R.id.pager2);
viewPager1.setAdapter(new MyAdapter1(getSupportFragmentManager()));
viewPager2.setAdapter(new MyAdapter2(getSupportFragmentManager()));
viewPager1.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
viewPager2.onTouchEvent(event);
return false;
}
});
viewPager2.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
viewPager1.onTouchEvent(event);
return false;
}
});
}
if you got
09-19 05:49:29.313: E/AndroidRuntime(1272): java.lang.IllegalArgumentException: pointerIndex out of range
try:
in your layout file you must use <package name of HackyViewPager.HackyViewPager instead of <android.support.v4.view.ViewPager
public class HackyViewPager extends ViewPager {
public HackyViewPager(Context context) {
super(context);
}
public HackyViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
try {
return super.onInterceptTouchEvent(ev);
} catch (IllegalArgumentException e) {
e.printStackTrace();
return false;
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
try {
return super.onTouchEvent(event);
}catch (IllegalArgumentException e) {
e.printStackTrace();
return false;
}
}
}
Reference:
Controlling two ViewPager Together
Related
I have only a simple MyGestureOverlayView extends GestureOverlayView in my layout; I want that when the user swipes and the GestureOverlayView recognizes the gesture, it doesn't change color. I want that the color will change only when I call overlay.setGestureColor(int color), but in fact this method changes the color that will have the next gesture when recognized by the super class, not while the user is swiping.
So my question is: how can I change the color of the gesture while the user is performing the gesture?
public class MyGestureOverlayView extends GestureOverlayView implements
GestureOverlayView.OnGesturePerformedListener,
GestureOverlayView.OnGestureListener {
private static final String TAG = MyGestureOverlayView.class.getName();
private GiocoActivity mContext;
private boolean mRecognized;
private GestureLibrary gestures;
public MyGestureOverlayView(Context context, AttributeSet attrs) {
super(context, attrs);
if (context instanceof GiocoActivity)
mContext = (GiocoActivity) context;
gestures = GestureLibraries.fromRawResource(mContext, R.raw.gesture);
if (!gestures.load())
mContext.finish();
addOnGesturePerformedListener(this);
addOnGestureListener(this);
}
#Override
public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
ArrayList<Prediction> predictions = gestures.recognize(gesture);
Log.d(TAG, "Gesture riconosciuta!");
// Sorry for my English :)
if (predictions.size() > 0 && predictions.get(0).score > 3.0) {
overlay.setGestureColor(Color.GREEN);
// The color doesn't change here, but it will change in the next gesture
String action = predictions.get(0).name;
mRecognized = true;
Toast.makeText(mContext, action, Toast.LENGTH_SHORT).show();
}
else {
overlay.setGestureColor(Color.RED);
// The color doesn't change here, but it will change in the next gesture
mRecognized = false;
}
Log.d(TAG, "Fine riconoscimento Gesture; esito: "+ mRecognized);
}
#Override
public void onGestureStarted(GestureOverlayView overlay, MotionEvent event) {
Log.d(TAG, "Gesture iniziata!");
}
#Override
public void onGesture(GestureOverlayView overlay, MotionEvent event) {
Log.d(TAG, "Gesture in corso!");
if (mRecognized) // Always false for the first gesture
overlay.setGestureColor(Color.GREEN); // Same as before
else
overlay.setGestureColor(Color.RED); // Same as before
}
#Override
public void onGestureEnded(GestureOverlayView overlay, MotionEvent event) {
Log.d(TAG, "Gesture finita!");
}
#Override
public void onGestureCancelled(GestureOverlayView overlay, MotionEvent event) {
Log.d(TAG, "Gesture cancellata!");
}
}
Besides, the callback method onGesturePerformed is called after onGestureEnded, so the boolean mRecognized in onGesture() is always false whem I perform a gesture for the first time and when it'll be recognized from the super class it'll be displayed red in any case (both recognized or not by my onGesturePerformedListener).
Sorry if I was complicate, this is my first question, and I found only one question similar to this, but it has no answers.
Thanks for your time.
I have successfully implemented the on scroll toolbar Hide/Show but i am stuck at onTouch Hide/Show toolbar. i have researched many related questions but nothing works for me. I want my toolbar to hide when user touches on screen and again shows when the screen is touched again, please help
I am using Android Studio
below is my OnScrollListener java class
this.mrecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
int mLastFirstVisibleItem = 0;
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
final int currentFirstVisibleItem = layout.findFirstVisibleItemPosition();
if (currentFirstVisibleItem > this.mLastFirstVisibleItem) {
HomePage.this.getSupportActionBar().hide();
} else if (currentFirstVisibleItem < this.mLastFirstVisibleItem) {
HomePage.this.getSupportActionBar().show();
}
this.mLastFirstVisibleItem = currentFirstVisibleItem;
}
});
Updated
mrecyclerView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
ActionBar actionBar = getSupportActionBar();
if(actionBar.isShowing()) {
actionBar.hide();
} else
actionBar.show();
return false;
}
});
this code works, but the problem now is that whenever i touch the screen it shows the toolbar and when i pick up my finger it hide itself, and as i am using RecyclerView it is getting difficult to scroll with all that showing and hiding. please help to make it stable so that if i touch once it stays shown and on another touch it hides itself.
here you go. This should work :)
layout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (actionBar.isShowing()) {
actionBar.hide();
} else {
actionBar.show();
}
return true;
} else return false;
}
});
Use onTouchListener to your root layout. And write your code inside callback.
I have a weird problem.
Achieved
I have 4 Fragments in a ViewPager attached with TabLayout. The first one is QR-code Scanner, which shows a camera. I wanted to start camera only when the Fragment is visible. For this, I override the Fragment's method setUserVisibleHint.
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser) {
checkPermissionForCamera(); //it checks permission and start camera
} else {
stopCamera();
}
}
And it's working absolutely fine.
Desired
Now, what I want to achieve is that when Fragment is not visible (or is being visible by scrolling), it shows a view with background over camera, so that instead of camera, that cover is visible. Like image below.
For it, I edited startCamera and stopCamera, now it looks like below,
public void startCamera() {
if(cameraCover != null)
cameraCover.setVisibility(View.GONE);
isCameraStarted = true;
mScannerView.setResultHandler(this); // Register ourselves as a handler for scan results.
mScannerView.startCamera();
}
public void stopCamera() {
if(cameraCover != null)
cameraCover.setVisibility(View.VISIBLE);
if(mScannerView != null) {
isCameraStarted = false;
mScannerView.stopCamera();// Stop camera on pause
mScannerView.stopCameraPreview();// Stop camera preview
}
}
But the gray cover is only visible for the first time, rest of the time I get the camera opened with view on which it's scrolled, like below.
I've also tried to override onPageScrolled of OnPageChangeListener, but with no luck. Here's what I've done.
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if(position == 0) {
if(positionOffset > 0.7) {
fragment = adapter.getItemAtPosition(0); //fragment is at zero
if(fragment != null) {
if(fragment instanceof ScanQRFragment) {
((ScanQRFragment) fragment).stopCamera();
}
}
}
}
}
#Override
public void onPageSelected(int position) {
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
Try either of the following ways :
1- override setMenuVisibility :
#Override
public void setMenuVisibility(final boolean visible) {
if (visible) {
//start camera preview
}
super.setMenuVisibility(visible);
}
2- Check yourFragment.isResumed() instead of isVisible()
I've been building controls for the vehicle I want to control. However I'm still quite new to Java and android developing. So I am looking for best practices to handle multiple buttons from the UI. So far I've managed to create 2 buttons which are on the same screen, see code below. Is this a correct way to handle and create buttons?
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/* Left Button */
Button btnLeft = (Button)findViewById(R.id.btnLeft);
btnLeft.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
// Create thread
case MotionEvent.ACTION_UP:
// End Thread
}
return false;
}
});
/* Right button */
Button btnRight = (Button)findViewById(R.id.btnRight);
btnRight.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
// Create thread
case MotionEvent.ACTION_UP:
// End Thread
}
return false;
}
});
}
}
That code actually works - I'm planning to create threads inside the switch-case statements too, I haven't figured out that one yet. Any input would be appreciated.
step 1 : make activity implement OnClickListener
step 2 : override the method onClick
public class MainActivity extends Activity implements OnClickListener {
Button btnLeft, btnRight;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/* Left Button */
btnLeft = (Button) findViewById(R.id.btnLeft);
btnLeft.setOnTouchListener(this);
/* Right button */
btnRight = (Button) findViewById(R.id.btnRight);
btnRight.setOnTouchListener(this);
}
#Override
public void onClick(View v) {
if (v == btnleft) {
// do stuff for button left
}
if (v == btnRight) {
// do stuff for button right
}
}
}
I'm using 3 Fragments inside a Viewpager, the problem is that I am loading big data in an Asynctask and loaders. On devices like HTC one, it works fine, however, on low-end devices, it takes a lot of time. This is mainly because when I implement the pagerAdapter, I put the Fragments inside an ArrayList, this force the fragments instantiate when the main activity is loaded. What I need is that it just "load" the first fragment (main) and when the user Swype, load the other fragment. its any way to achieve this? this is my pageAdapater
public class PagerAdapter extends FragmentPagerAdapter {
private final ArrayList<Fragment> mFragments = new ArrayList<Fragment>();
// private final ArrayList<String> titulos = new ArrayList<String>();
// private int NUM_PAGES =0;
public PagerAdapter(FragmentManager manager,int num_pages) {
super(manager);
// this.NUM_PAGES = num_pages;
}
public void addFragment(Fragment fragment,String title) {
mFragments.add(fragment);
notifyDataSetChanged();
}
#Override
public int getCount() {
//return NUM_PAGES;
return mFragments.size();
}
#Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
}
The above method from Sun did not work for me (maybe it does for you), but I thought I would share my edit of his method also. Very good method by the way Sun!
private boolean _hasLoadedOnce= false; // your boolean field
#Override
public void setUserVisibleHint(boolean isFragmentVisible_) {
super.setUserVisibleHint(true);
if (this.isVisible()) {
// we check that the fragment is becoming visible
if (isFragmentVisible_ && !_hasLoadedOnce) {
new NetCheck().execute();
_hasLoadedOnce = true;
}
}
}
I'm gonna add my solution here since I faced a similar issue. My asynchronous task wasn't loading huge amounts of data, but it prevents unnecessary network calls. Here's what I added in my Fragment:
private boolean _hasLoadedOnce= false; // your boolean field
#Override
public void setUserVisibleHint(boolean isFragmentVisible_) {
super.setUserVisibleHint(isVisibleToUser);
if (this.isVisible()) {
// we check that the fragment is becoming visible
if (!isFragmentVisible_ && !_hasLoadedOnce) {
//run your async task here since the user has just focused on your fragment
_hasLoadedOnce = true;
}
}
}
With the above code, your Fragment will be loaded, but your async task will not run until the user actually scrolls to the Fragment for the first time. Once displayed, your async task will run for the first time automatically. Then you can provide a way to load more data via a button or pull to refresh. The above Fragment was in my ViewPager and seemed to work fine.
Slightly modified version to fix potential NPE caused by some views not fully initialised
private boolean _hasLoadedOnce= false; // your boolean field
#Override
public void setUserVisibleHint(boolean isFragmentVisible_) {
super.setUserVisibleHint(isVisibleToUser);
if (this.isVisible()) {
// we check that the fragment is becoming visible
if (!isFragmentVisible_ && !_hasLoadedOnce) {
new Handler().post(() -> {
makeAsyncRequest();//do your asyn stuffs
_hasLoadedOnce = true;
});
}
}
}
Use fragmentStatePageAdapter if you have a lot of pages and you want to destroy them when not visible.
It has implemented a setMenuVisibility(boolean menuVisible) when fragment becomes visible, so use that.
I might be late for the party but here's my solution and it works as expected. In all of your child fragments create a boolean variable:
private boolean loadFragmentExecuted = false;
in the child fragments create a generic method called loadFragment and move all of the logic you added in onCreateView to that method:
public void loadFragment()
{
if(!loadFragmentExecuted)
{
//Add your logic to manipulate the UI or load data etc...
loadFragmentExecuted = true;
}
}
in your pageview logic create the fragments dynamically like:
//add the fragment
String fragmentName = "com.something." + fragmentId;
//check if the class exists
try
{
Class myFragmentClass = Class.forName(fragmentName);
Fragment myFragment = (Fragment) myFragmentClass.newInstance();
mFragments.add(myFragment);
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}
catch (InstantiationException e)
{
e.printStackTrace();
}
then set your pager adapter and attach a tablayout with it:
//set our pager adapter that contains different fragments
mPagerAdapter = new BasePagerAdapter(mFragmentManager, mFragments);
//link the adapter to the viewpager
mViewPager.setAdapter(mPagerAdapter);
//cache fragments
int limit = (mPagerAdapter.getCount() > 0 ? mPagerAdapter.getCount() : 1);
mViewPager.setOffscreenPageLimit(limit);
//add the page listner to the viewPager and link it to the tabLayout
mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(mTabLayout));
//on tab selected select current viewpager item
mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener()
{
#Override
public void onTabSelected(TabLayout.Tab tab)
{
mViewPager.setCurrentItem(tab.getPosition());
//get fragment for the selected tab
Fragment f = mPagerAdapter.getItem(tab.getPosition());
//load the content of the fragment
try
{
Class c = f.getClass();
Method loadFragment = c.getMethod("loadFragment");
loadFragment.invoke(f);
}
catch (IllegalAccessException e){}
catch (InvocationTargetException e){}
catch (NoSuchMethodException e){}
}
#Override
public void onTabUnselected(TabLayout.Tab tab)
{
}
#Override
public void onTabReselected(TabLayout.Tab tab)
{
}
});