You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
256 lines
10 KiB
256 lines
10 KiB
/*
|
|
* Copyright (C) 2011 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.example.android.hcgallery;
|
|
|
|
import android.app.ActionBar;
|
|
import android.app.Activity;
|
|
import android.app.FragmentTransaction;
|
|
import android.app.ListFragment;
|
|
import android.content.ClipData;
|
|
import android.content.res.TypedArray;
|
|
import android.graphics.Canvas;
|
|
import android.graphics.Color;
|
|
import android.graphics.drawable.Drawable;
|
|
import android.os.Bundle;
|
|
import android.view.View;
|
|
import android.view.ViewTreeObserver;
|
|
import android.widget.AdapterView;
|
|
import android.widget.AdapterView.OnItemLongClickListener;
|
|
import android.widget.ArrayAdapter;
|
|
import android.widget.FrameLayout;
|
|
import android.widget.FrameLayout.LayoutParams;
|
|
import android.widget.ListView;
|
|
import android.widget.TextView;
|
|
|
|
/**
|
|
* Fragment that shows the list of images
|
|
* As an extension of ListFragment, this fragment uses a default layout
|
|
* that includes a single ListView, which you can acquire with getListView()
|
|
* When running on a screen size smaller than "large", this fragment appears alone
|
|
* in MainActivity. In this case, selecting a list item opens the ContentActivity,
|
|
* which likewise holds only the ContentFragment.
|
|
*/
|
|
public class TitlesFragment extends ListFragment implements ActionBar.TabListener {
|
|
OnItemSelectedListener mListener;
|
|
private int mCategory = 0;
|
|
private int mCurPosition = 0;
|
|
private boolean mDualFragments = false;
|
|
|
|
/** Container Activity must implement this interface and we ensure
|
|
* that it does during the onAttach() callback
|
|
*/
|
|
public interface OnItemSelectedListener {
|
|
public void onItemSelected(int category, int position);
|
|
}
|
|
|
|
@Override
|
|
public void onAttach(Activity activity) {
|
|
super.onAttach(activity);
|
|
// Check that the container activity has implemented the callback interface
|
|
try {
|
|
mListener = (OnItemSelectedListener) activity;
|
|
} catch (ClassCastException e) {
|
|
throw new ClassCastException(activity.toString()
|
|
+ " must implement OnItemSelectedListener");
|
|
}
|
|
}
|
|
|
|
/** This is where we perform setup for the fragment that's either
|
|
* not related to the fragment's layout or must be done after the layout is drawn.
|
|
* Notice that this fragment does not implement onCreateView(), because it extends
|
|
* ListFragment, which includes a ListView as the root view by default, so there's
|
|
* no need to set up the layout.
|
|
*/
|
|
@Override
|
|
public void onActivityCreated(Bundle savedInstanceState) {
|
|
super.onActivityCreated(savedInstanceState);
|
|
|
|
ContentFragment frag = (ContentFragment) getFragmentManager()
|
|
.findFragmentById(R.id.content_frag);
|
|
if (frag != null) mDualFragments = true;
|
|
|
|
ActionBar bar = getActivity().getActionBar();
|
|
bar.setDisplayHomeAsUpEnabled(false);
|
|
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
|
|
|
|
// Must call in order to get callback to onCreateOptionsMenu()
|
|
setHasOptionsMenu(true);
|
|
|
|
Directory.initializeDirectory();
|
|
for (int i = 0; i < Directory.getCategoryCount(); i++) {
|
|
bar.addTab(bar.newTab().setText(Directory.getCategory(i).getName())
|
|
.setTabListener(this));
|
|
}
|
|
|
|
//Current position should survive screen rotations.
|
|
if (savedInstanceState != null) {
|
|
mCategory = savedInstanceState.getInt("category");
|
|
mCurPosition = savedInstanceState.getInt("listPosition");
|
|
bar.selectTab(bar.getTabAt(mCategory));
|
|
}
|
|
|
|
populateTitles(mCategory);
|
|
ListView lv = getListView();
|
|
lv.setCacheColorHint(Color.TRANSPARENT); // Improves scrolling performance
|
|
|
|
if (mDualFragments) {
|
|
// Highlight the currently selected item
|
|
lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
|
|
// Enable drag and dropping
|
|
lv.setOnItemLongClickListener(new OnItemLongClickListener() {
|
|
public boolean onItemLongClick(AdapterView<?> av, View v, int pos, long id) {
|
|
final String title = (String) ((TextView) v).getText();
|
|
|
|
// Set up clip data with the category||entry_id format.
|
|
final String textData = String.format("%d||%d", mCategory, pos);
|
|
ClipData data = ClipData.newPlainText(title, textData);
|
|
v.startDrag(data, new MyDragShadowBuilder(v), null, 0);
|
|
return true;
|
|
}
|
|
});
|
|
}
|
|
|
|
// If showing both fragments, select the appropriate list item by default
|
|
if (mDualFragments) selectPosition(mCurPosition);
|
|
|
|
// Attach a GlobalLayoutListener so that we get a callback when the layout
|
|
// has finished drawing. This is necessary so that we can apply top-margin
|
|
// to the ListView in order to dodge the ActionBar. Ordinarily, that's not
|
|
// necessary, but we've set the ActionBar to "overlay" mode using our theme,
|
|
// so the layout does not account for the action bar position on its own.
|
|
ViewTreeObserver observer = getListView().getViewTreeObserver();
|
|
observer.addOnGlobalLayoutListener(layoutListener);
|
|
}
|
|
|
|
@Override
|
|
public void onDestroyView() {
|
|
super.onDestroyView();
|
|
// Always detach ViewTreeObserver listeners when the view tears down
|
|
getListView().getViewTreeObserver().removeGlobalOnLayoutListener(layoutListener);
|
|
}
|
|
|
|
/** Attaches an adapter to the fragment's ListView to populate it with items */
|
|
public void populateTitles(int category) {
|
|
DirectoryCategory cat = Directory.getCategory(category);
|
|
String[] items = new String[cat.getEntryCount()];
|
|
for (int i = 0; i < cat.getEntryCount(); i++)
|
|
items[i] = cat.getEntry(i).getName();
|
|
// Convenience method to attach an adapter to ListFragment's ListView
|
|
setListAdapter(new ArrayAdapter<String>(getActivity(),
|
|
R.layout.title_list_item, items));
|
|
mCategory = category;
|
|
}
|
|
|
|
@Override
|
|
public void onListItemClick(ListView l, View v, int position, long id) {
|
|
// Send the event to the host activity via OnItemSelectedListener callback
|
|
mListener.onItemSelected(mCategory, position);
|
|
mCurPosition = position;
|
|
}
|
|
|
|
/** Called to select an item from the listview */
|
|
public void selectPosition(int position) {
|
|
// Only if we're showing both fragments should the item be "highlighted"
|
|
if (mDualFragments) {
|
|
ListView lv = getListView();
|
|
lv.setItemChecked(position, true);
|
|
}
|
|
// Calls the parent activity's implementation of the OnItemSelectedListener
|
|
// so the activity can pass the event to the sibling fragment as appropriate
|
|
mListener.onItemSelected(mCategory, position);
|
|
}
|
|
|
|
@Override
|
|
public void onSaveInstanceState (Bundle outState) {
|
|
super.onSaveInstanceState(outState);
|
|
outState.putInt("listPosition", mCurPosition);
|
|
outState.putInt("category", mCategory);
|
|
}
|
|
|
|
/** This defines how the draggable list items appear during a drag event */
|
|
private class MyDragShadowBuilder extends View.DragShadowBuilder {
|
|
private Drawable mShadow;
|
|
|
|
public MyDragShadowBuilder(View v) {
|
|
super(v);
|
|
|
|
final TypedArray a = v.getContext().obtainStyledAttributes(R.styleable.AppTheme);
|
|
mShadow = a.getDrawable(R.styleable.AppTheme_listDragShadowBackground);
|
|
mShadow.setCallback(v);
|
|
mShadow.setBounds(0, 0, v.getWidth(), v.getHeight());
|
|
a.recycle();
|
|
}
|
|
|
|
@Override
|
|
public void onDrawShadow(Canvas canvas) {
|
|
super.onDrawShadow(canvas);
|
|
mShadow.draw(canvas);
|
|
getView().draw(canvas);
|
|
}
|
|
}
|
|
|
|
// Because the fragment doesn't have a reliable callback to notify us when
|
|
// the activity's layout is completely drawn, this OnGlobalLayoutListener provides
|
|
// the necessary callback so we can add top-margin to the ListView in order to dodge
|
|
// the ActionBar. Which is necessary because the ActionBar is in overlay mode, meaning
|
|
// that it will ordinarily sit on top of the activity layout as a top layer and
|
|
// the ActionBar height can vary. Specifically, when on a small/normal size screen,
|
|
// the action bar tabs appear in a second row, making the action bar twice as tall.
|
|
ViewTreeObserver.OnGlobalLayoutListener layoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
|
|
@Override
|
|
public void onGlobalLayout() {
|
|
int barHeight = getActivity().getActionBar().getHeight();
|
|
ListView listView = getListView();
|
|
FrameLayout.LayoutParams params = (LayoutParams) listView.getLayoutParams();
|
|
// The list view top-margin should always match the action bar height
|
|
if (params.topMargin != barHeight) {
|
|
params.topMargin = barHeight;
|
|
listView.setLayoutParams(params);
|
|
}
|
|
// The action bar doesn't update its height when hidden, so make top-margin zero
|
|
if (!getActivity().getActionBar().isShowing()) {
|
|
params.topMargin = 0;
|
|
listView.setLayoutParams(params);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
/* The following are callbacks implemented for the ActionBar.TabListener,
|
|
* which this fragment implements to handle events when tabs are selected.
|
|
*/
|
|
|
|
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
|
|
TitlesFragment titleFrag = (TitlesFragment) getFragmentManager()
|
|
.findFragmentById(R.id.titles_frag);
|
|
titleFrag.populateTitles(tab.getPosition());
|
|
|
|
if (mDualFragments) {
|
|
titleFrag.selectPosition(0);
|
|
}
|
|
}
|
|
|
|
/* These must be implemented, but we don't use them */
|
|
|
|
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
|
|
}
|
|
|
|
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
|
|
}
|
|
|
|
}
|