Finished implementation of swipe to change tabs.

This commit is contained in:
Peter Serwylo 2013-04-10 12:39:28 +10:00
parent fdf69cabcc
commit 89facb24c6
5 changed files with 185 additions and 75 deletions

View File

@ -1,23 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fdroid_layout"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:orientation="vertical">-->
android:orientation="vertical">
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_pager"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<!--<android.support.v4.view.PagerTitleStrip
android:id="@+id/main_pager_title"
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_pager"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:background="#33b5e5"
android:textColor="#fff"
android:paddingTop="4dp"
android:paddingBottom="4dp" />-->
android:layout_height="fill_parent">
</android.support.v4.view.ViewPager>
</android.support.v4.view.ViewPager>
</LinearLayout>

View File

@ -29,14 +29,11 @@ import android.app.*;
import android.os.Build;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.PagerTitleStrip;
import android.support.v4.view.ViewPager;
import android.view.*;
import android.widget.*;
import org.fdroid.fdroid.DB.App;
import org.fdroid.fdroid.R;
import android.R.drawable;
import android.app.AlertDialog.Builder;
import android.content.DialogInterface;
import android.content.Intent;
@ -49,15 +46,11 @@ import android.os.Handler;
import android.os.ResultReceiver;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.TabHost.TabSpec;
import org.fdroid.fdroid.views.AppListFragmentStatePageAdapter;
import org.fdroid.fdroid.views.AppListFragmentPageAdapter;
import org.fdroid.fdroid.views.AppListView;
public class FDroid extends FragmentActivity implements OnItemClickListener,
OnItemSelectedListener {
@ -97,6 +90,9 @@ public class FDroid extends FragmentActivity implements OnItemClickListener,
private ViewPager viewPager;
// Used by pre 3.0 devices which don't have an ActionBar...
private TabHost tabHost;
// The following getters
// (availableAdapter/installedAdapter/canUpdateAdapter/categoriesAdapter)
// are used by the APpListViewFactory to construct views that can be used
@ -123,14 +119,15 @@ public class FDroid extends FragmentActivity implements OnItemClickListener,
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fdroid);
// Needs to be created before createViews(), because that will use the
// getCategoriesAdapter() accessor which expects this object...
categories = new ArrayAdapter<String>(
this, android.R.layout.simple_spinner_item, new Vector<String>());
categories.setDropDownViewResource(
android.R.layout.simple_spinner_dropdown_item);
categories = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, new Vector<String>());
categories
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
createViews();
createTabs();
@ -141,9 +138,9 @@ public class FDroid extends FragmentActivity implements OnItemClickListener,
call.putExtra("uri", i.getStringExtra("uri"));
startActivityForResult(call, REQUEST_MANAGEREPOS);
} else if (i.hasExtra(EXTRA_TAB_UPDATE)) {
boolean updateTab = i.getBooleanExtra(EXTRA_TAB_UPDATE, false);
if (updateTab) {
tabHost.setCurrentTab(2);
boolean showUpdateTab = i.getBooleanExtra(EXTRA_TAB_UPDATE, false);
if (showUpdateTab) {
selectTab(2);
}
}
@ -284,7 +281,12 @@ public class FDroid extends FragmentActivity implements OnItemClickListener,
private void createViews() {
viewPager = (ViewPager)findViewById(R.id.main_pager);
viewPager.setAdapter(new AppListFragmentStatePageAdapter(this));
viewPager.setAdapter(new AppListFragmentPageAdapter(this));
viewPager.setOnPageChangeListener( new ViewPager.SimpleOnPageChangeListener() {
public void onPageSelected(int position) {
selectTab(position);
}
});
}
private void createTabs() {
@ -295,6 +297,14 @@ public class FDroid extends FragmentActivity implements OnItemClickListener,
}
}
private void selectTab(int index) {
if (Build.VERSION.SDK_INT >= 11) {
getActionBar().setSelectedNavigationItem(index);
} else {
tabHost.setCurrentTab(index);
}
}
private void updateTabText(int index) {
CharSequence text = viewPager.getAdapter().getPageTitle(index);
if ( Build.VERSION.SDK_INT >= 11) {
@ -328,17 +338,70 @@ public class FDroid extends FragmentActivity implements OnItemClickListener,
}
}));
}
pager.setOnPageChangeListener( new ViewPager.SimpleOnPageChangeListener() {
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
});
}
/**
* There is a bit of boiler-plate code required to get a TabWidget showing,
* which includes creating a TabHost, populating it with the TabWidget,
* and giving it a FrameLayout as a child. This will make the tabs have
* dummy empty contents and then hook them up to our ViewPager.
*/
private void createOldTabs() {
tabHost = new TabHost(this);
tabHost.setLayoutParams(new TabHost.LayoutParams(
TabHost.LayoutParams.MATCH_PARENT, TabHost.LayoutParams.WRAP_CONTENT));
TabWidget tabWidget = new TabWidget(this);
tabWidget.
tabWidget.setId(android.R.id.tabs);
tabHost.setLayoutParams(new TabHost.LayoutParams(
TabWidget.LayoutParams.MATCH_PARENT, TabWidget.LayoutParams.WRAP_CONTENT));
FrameLayout layout = new FrameLayout(this);
layout.setId(android.R.id.tabcontent);
layout.setLayoutParams(new TabWidget.LayoutParams(0, 0));
tabHost.addView(tabWidget);
tabHost.addView(layout);
tabHost.setup();
TabHost.TabContentFactory factory = new TabHost.TabContentFactory() {
@Override
public View createTabContent(String tag) {
return new View(FDroid.this);
}
};
TabSpec availableTabSpec = tabHost.newTabSpec("available")
.setIndicator(
getString(R.string.tab_noninstalled),
getResources().getDrawable(android.R.drawable.ic_input_add))
.setContent(factory);
TabSpec installedTabSpec = tabHost.newTabSpec("installed")
.setIndicator(
getString(R.string.tab_installed),
getResources().getDrawable(android.R.drawable.star_off))
.setContent(factory);
TabSpec canUpdateTabSpec = tabHost.newTabSpec("canUpdate")
.setIndicator(
getString(R.string.tab_updates),
getResources().getDrawable(android.R.drawable.star_on))
.setContent(factory);
tabHost.addTab(availableTabSpec);
tabHost.addTab(installedTabSpec);
tabHost.addTab(canUpdateTabSpec);
LinearLayout contentView = (LinearLayout)findViewById(R.id.fdroid_layout);
contentView.addView(tabHost, 0);
tabHost.setOnTabChangedListener( new TabHost.OnTabChangeListener() {
@Override
public void onTabChanged(String tabId) {
viewPager.setCurrentItem(tabHost.getCurrentTab());
}
});
}
// Populate the lists.
@ -530,17 +593,13 @@ public class FDroid extends FragmentActivity implements OnItemClickListener,
public void onItemClick(AdapterView<?> arg0, View arg1, final int arg2,
long arg3) {
ViewPager pager = (ViewPager)findViewById(R.id.main_pager);
Fragment fragment = ((AppListFragmentPageAdapter)viewPager.getAdapter()).getItem(viewPager.getCurrentItem());
final DB.App app;
String curtab = tabHost.getCurrentTabTag();
if (curtab.equalsIgnoreCase(TAB_Installed)) {
app = (DB.App) apps_in.getItem(arg2);
} else if (curtab.equalsIgnoreCase(TAB_Updates)) {
app = (DB.App) apps_up.getItem(arg2);
} else {
app = (DB.App) apps_av.getItem(arg2);
}
// The fragment.getView() returns a wrapper object which has the
// actual view we're interested in inside:
// http://stackoverflow.com/a/13684505
AppListView view = ((AppListView)((ViewGroup)fragment.getView()).getChildAt(0));
final DB.App app = (DB.App)view.getAppList().getAdapter().getItem(arg2);
Intent intent = new Intent(this, AppDetails.class);
intent.putExtra("appid", app.id);

View File

@ -2,19 +2,23 @@ package org.fdroid.fdroid.views;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.app.FragmentPagerAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import org.fdroid.fdroid.FDroid;
import org.fdroid.fdroid.R;
public class AppListFragmentStatePageAdapter extends FragmentStatePagerAdapter {
/**
* Used by the FDroid activity in conjunction with its ViewPager to support
* swiping of tabs for both old devices (< 3.0) and new devices.
*/
public class AppListFragmentPageAdapter extends FragmentPagerAdapter {
private FDroid parent;
private Fragment[] fragments = new Fragment[3];
public AppListFragmentStatePageAdapter(FDroid parent) {
public AppListFragmentPageAdapter(FDroid parent) {
super(parent.getSupportFragmentManager());
this.parent = parent;
@ -57,7 +61,7 @@ public class AppListFragmentStatePageAdapter extends FragmentStatePagerAdapter {
return parent.getString(R.string.tab_installed);
case 2:
String updates = parent.getString(R.string.tab_updates);
updates += " (" + parent.getCanUpdateAdapter() + ")";
updates += " (" + parent.getCanUpdateAdapter().getCount() + ")";
return updates;
default:
return "";

View File

@ -0,0 +1,32 @@
package org.fdroid.fdroid.views;
import android.content.Context;
import android.widget.LinearLayout;
import android.widget.ListView;
/**
* There are three main app-lists in the UI:
* - Available
* - Installed
* - Apps which can be updated
* This class provides a View which knows about these app lists, but can have
* different contents (e.g. a drop down list of categories). It allows us to
* get a reference to the selected item in the FDroid Activity, without having
* to know which list we are actually looking at.
*/
public class AppListView extends LinearLayout {
private ListView appList;
public AppListView(Context context) {
super(context);
}
public void setAppList(ListView appList) {
this.appList = appList;
}
public ListView getAppList() {
return appList;
}
}

View File

@ -2,7 +2,6 @@ package org.fdroid.fdroid.views;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.Spinner;
@ -10,6 +9,10 @@ import org.fdroid.fdroid.AppListAdapter;
import org.fdroid.fdroid.FDroid;
import org.fdroid.fdroid.R;
/**
* Provides functionality to create the three lists of applications
* required for the FDroid activity.
*/
public class AppListViewFactory {
private FDroid parent;
@ -18,32 +21,52 @@ public class AppListViewFactory {
this.parent = parent;
}
public View createAvailableView() {
ListView list = createAppListView(parent.getAvailableAdapter());
LinearLayout view = new LinearLayout(parent);
public AppListView createAvailableView() {
AppListView view = new AppListView(parent);
view.setOrientation(LinearLayout.VERTICAL);
Spinner cats = new Spinner(parent);
Spinner spinner = new Spinner(parent);
// Giving it an ID lets the default save/restore state
// functionality do its stuff.
cats.setId(R.id.categorySpinner);
cats.setAdapter(parent.getCategoriesAdapter());
cats.setOnItemSelectedListener(parent);
view.addView(cats, new ViewGroup.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
view.addView(list, new ViewGroup.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT,
LinearLayout.LayoutParams.FILL_PARENT));
spinner.setId(R.id.categorySpinner);
spinner.setAdapter(parent.getCategoriesAdapter());
spinner.setOnItemSelectedListener(parent);
view.addView(
spinner,
new ViewGroup.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
ListView list = createAppListView(parent.getAvailableAdapter());
view.setAppList(list);
view.addView(
list,
new ViewGroup.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT));
return view;
}
public View createInstalledView() {
return createAppListView(parent.getInstalledAdapter());
public AppListView createInstalledView() {
return createPlainAppList(parent.getInstalledAdapter());
}
public View createCanUpdateView() {
return createAppListView(parent.getCanUpdateAdapter());
public AppListView createCanUpdateView() {
return createPlainAppList(parent.getCanUpdateAdapter());
}
protected AppListView createPlainAppList(AppListAdapter adapter) {
AppListView view = new AppListView(parent);
ListView list = createAppListView(adapter);
view.addView(
list,
new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
view.setAppList(list);
return view;
}
protected ListView createAppListView(AppListAdapter adapter) {