Android Fragment + ViewPager
Source: StackOverflow, StackOverflow, Blog
Requirement: we will create a custom ViewPager
class that allow enable/disable spiwing. This ViewPager
contains 3 fragments MyCameraFragment
, PhotoFragment
, MissionFragment
. The MyCameraFragment
is the special one. We will need to enable auto orientation (sensor) only for this fragment.
Answer:
MyViewPager
public class MyViewPager extends ViewPager {
private boolean enabled;
public MyViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
this.enabled = true;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (this.enabled) {
return super.onTouchEvent(event);
}
return false;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (this.enabled) {
return super.onInterceptTouchEvent(event);
}
return false;
}
public void setPagingEnabled(boolean enabled) {
this.enabled = enabled;
}
}
On your main activity, HomeActivity
in this case:
private void initUI() {
// set content view
setContentView(R.layout.activity_home);
// Instantiate a ViewPager and a PagerAdapter.
mPager = (MyViewPager) findViewById(R.id.pager);
mPagerAdapter = new MyPagerAdapter(getSupportFragmentManager(), this);
mPager.setAdapter(mPagerAdapter);
mPager.setOffscreenPageLimit(3);
mPager.setCurrentItem(MyPagerAdapter.PHOTO_FRAGMENT);
mPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
if(position == MyPagerAdapter.CAMERA_FRAGMENT){
DisplayUtil.setAutoOrientationEnabled(getApplicationContext(), true); //enable auto orientation
DisplayUtil.keepScreenOn(HomeActivity.this);
}else{
DisplayUtil.setAutoOrientationEnabled(getApplicationContext(), false); //disable auto orientation
DisplayUtil.clearKeepScreenOn(HomeActivity.this);
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
//disable page swiping if the camera is in landscape mode
if(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE){
mPager.setPagingEnabled(false);
}else{
mPager.setPagingEnabled(true);
}
mPager.setCurrentItem(MyPagerAdapter.CAMERA_FRAGMENT);
}
//util methods
public static void setAutoOrientationEnabled(Context context, boolean enabled) {
Settings.System.putInt(context.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, enabled ? 1 : 0);
}
public static void keepScreenOn(Activity act) {
act.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
public static void clearKeepScreenOn(Activity act) {
act.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
MyPagerAdapter
public class MyPagerAdapter extends FragmentStatePagerAdapter {
public static final int CAMERA_FRAGMENT = 0;
public static final int PHOTO_FRAGMENT = 1;
public static final int MISSION_FRAGMENT = 2;
private static final int TOTAL_PAGE = 3;
private Context mContext;
//private SparseArray<Fragment> registeredFragmentList = new SparseArray<>();
public MyPagerAdapter(FragmentManager fm, Context ctx) {
super(fm);
mContext = ctx;
}
//see http://stackoverflow.com/a/29269509/1602807
@Override
public Fragment getItem(int position) {
// Do NOT try to save references to the Fragments in getItem(),
// because getItem() is not always called. If the Fragment
// was already created then it will be retrieved from the FragmentManger
// and not here (i.e. getItem() won't be called again).
switch (position) {
case CAMERA_FRAGMENT:
File output = new File(DiskUtil.getVideoFolder(), DiskUtil.getCameraVideoName());
return MyCameraFragment.newVideoInstance(Uri.fromFile(output),
true,
1, //AbstractCameraActivity.Quality.HIGH
0,
0);
case PHOTO_FRAGMENT:
return Fragment.instantiate(mContext, PhotoFragment.class.getName());
case MISSION_FRAGMENT:
return Fragment.instantiate(mContext, MissionFragment.class.getName());
default:
// This should never happen. Always account for each position above
return null;
}
}
@Override
public int getCount() {
return TOTAL_PAGE;
}
//enable this back if we want to access the current fragment in ViewPager
/*@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragmentList.put(position, fragment);
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragmentList.remove(position);
super.destroyItem(container, position, object);
}
*//**
* This method is used to get the current fragment out of the ViewPager (see http://stackoverflow.com/a/15261142/1602807)
* @param position
* @return the current Fragment
*//*
public Fragment getRegisteredFragment(int position) {
return registeredFragmentList.get(position);
}*/
}
MyCameraFragment
//manually handling configuration change, see http://blog.wittchen.biz.pl/how-to-change-fragment-layout-on-orientation-change/
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
LayoutInflater inflater = LayoutInflater.from(getActivity());
ViewGroup container = (ViewGroup) getView();
try {
container.removeAllViewsInLayout();
getPreparedUI(inflater, container, true); //this should be the one to do all the UI init stuffs
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return getPreparedUI(inflater, container, false);
}
private View getPreparedUI(LayoutInflater inflater, ViewGroup container, boolean isOnConfigurationChanged){
View v = null;
if(mHasFlash){
if(!isOnConfigurationChanged) {
v = inflater.inflate(R.layout.mycwac_cam2_fragment, container, false);
}else {
v = inflater.inflate(R.layout.mycwac_cam2_fragment, container, true);
}
}else{
if(!isOnConfigurationChanged) {
v = inflater.inflate(R.layout.mycwac_cam2_fragment_without_flash, container, false);
}else {
v = inflater.inflate(R.layout.mycwac_cam2_fragment_without_flash, container, true);
}
}
//other init stuffs
return v;
}
Finally in the AndroidManifest
we just need to tell the system we will handle the configuration change our self with this:
<activity android:name=".activities.HomeActivity" android:configChanges="orientation|screenSize"/>
Generally this is considered to be bad pratice, but since the ViewPager
automatically handle Fragment'states for us, we can't really do much with configuartion change. Maybe change to a different approach, see this