ActionBar Goole官方例子-HoneyCombGallery
2014-02-27 16:20
225 查看
例子源码
MainActivity:
MainActivity:
package com.example.android.hcgallery; /** This is the main "launcher" activity. * When running on a "large" or larger screen, this activity displays both the * TitlesFragments and the Content Fragment. When on a smaller screen size, this * activity displays only the TitlesFragment. In which case, selecting a list * item opens the ContentActivity, holds only the ContentFragment. */ public class MainActivity extends Activity implements TitlesFragment.OnItemSelectedListener { private Animator mCurrentTitlesAnimator; private String[] mToggleLabels = {"Show Titles", "Hide Titles"}; private static final int NOTIFICATION_DEFAULT = 1; private static final String ACTION_DIALOG = "com.example.android.hcgallery.action.DIALOG"; private int mThemeId = -1; private boolean mDualFragments = false; private boolean mTitlesHidden = false; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if(savedInstanceState != null) { if (savedInstanceState.getInt("theme", -1) != -1) { mThemeId = savedInstanceState.getInt("theme"); this.setTheme(mThemeId); } mTitlesHidden = savedInstanceState.getBoolean("titlesHidden"); } setContentView(R.layout.main); ActionBar bar = getActionBar(); bar.setDisplayShowTitleEnabled(false); ContentFragment frag = (ContentFragment) getFragmentManager() .findFragmentById(R.id.content_frag); if (frag != null) mDualFragments = true; if (mTitlesHidden) { getFragmentManager().beginTransaction() .hide(getFragmentManager().findFragmentById(R.id.titles_frag)).commit(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.main_menu, menu); // If the device doesn't support camera, remove the camera menu item if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) { menu.removeItem(R.id.menu_camera); } return true; } @Override public boolean onPrepareOptionsMenu(Menu menu) { // If not showing both fragments, remove the "toggle titles" menu item if (!mDualFragments) { menu.removeItem(R.id.menu_toggleTitles); } else { menu.findItem(R.id.menu_toggleTitles).setTitle(mToggleLabels[mTitlesHidden ? 0 : 1]); } return super.onPrepareOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_camera: Intent intent = new Intent(this, CameraActivity.class); intent.putExtra("theme", mThemeId); startActivity(intent); return true; case R.id.menu_toggleTitles: toggleVisibleTitles(); return true; case R.id.menu_toggleTheme: if (mThemeId == R.style.AppTheme_Dark) { mThemeId = R.style.AppTheme_Light; } else { mThemeId = R.style.AppTheme_Dark; } this.recreate(); return true; case R.id.menu_showDialog: showDialog("This is indeed an awesome dialog."); return true; case R.id.menu_showStandardNotification: showNotification(false); return true; case R.id.menu_showCustomNotification: showNotification(true); return true; default: return super.onOptionsItemSelected(item); } } /** Respond to the "toogle titles" item in the action bar */ public void toggleVisibleTitles() { // Use these for custom animations. final FragmentManager fm = getFragmentManager(); final TitlesFragment f = (TitlesFragment) fm .findFragmentById(R.id.titles_frag); final View titlesView = f.getView(); // Determine if we're in portrait, and whether we're showing or hiding the titles // with this toggle. final boolean isPortrait = getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT; final boolean shouldShow = f.isHidden() || mCurrentTitlesAnimator != null; // Cancel the current titles animation if there is one. if (mCurrentTitlesAnimator != null) mCurrentTitlesAnimator.cancel(); // Begin setting up the object animator. We'll animate the bottom or right edge of the // titles view, as well as its alpha for a fade effect. ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder( titlesView, PropertyValuesHolder.ofInt( isPortrait ? "bottom" : "right", shouldShow ? getResources().getDimensionPixelSize(R.dimen.titles_size) : 0), PropertyValuesHolder.ofFloat("alpha", shouldShow ? 1 : 0) ); // At each step of the animation, we'll perform layout by calling setLayoutParams. final ViewGroup.LayoutParams lp = titlesView.getLayoutParams(); objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { public void onAnimationUpdate(ValueAnimator valueAnimator) { // *** WARNING ***: triggering layout at each animation frame highly impacts // performance so you should only do this for simple layouts. More complicated // layouts can be better served with individual animations on child views to // avoid the performance penalty of layout. if (isPortrait) { lp.height = (Integer) valueAnimator.getAnimatedValue(); } else { lp.width = (Integer) valueAnimator.getAnimatedValue(); } titlesView.setLayoutParams(lp); } }); if (shouldShow) { fm.beginTransaction().show(f).commit(); objectAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animator) { mCurrentTitlesAnimator = null; mTitlesHidden = false; invalidateOptionsMenu(); } }); } else { objectAnimator.addListener(new AnimatorListenerAdapter() { boolean canceled; @Override public void onAnimationCancel(Animator animation) { canceled = true; super.onAnimationCancel(animation); } @Override public void onAnimationEnd(Animator animator) { if (canceled) return; mCurrentTitlesAnimator = null; fm.beginTransaction().hide(f).commit(); mTitlesHidden = true; invalidateOptionsMenu(); } }); } // Start the animation. objectAnimator.start(); mCurrentTitlesAnimator = objectAnimator; // Manually trigger onNewIntent to check for ACTION_DIALOG. onNewIntent(getIntent()); } @Override protected void onNewIntent(Intent intent) { if (ACTION_DIALOG.equals(intent.getAction())) { showDialog(intent.getStringExtra(Intent.EXTRA_TEXT)); } } void showDialog(String text) { // DialogFragment.show() will take care of adding the fragment // in a transaction. We also want to remove any currently showing // dialog, so make our own transaction and take care of that here. FragmentTransaction ft = getFragmentManager().beginTransaction(); DialogFragment newFragment = MyDialogFragment.newInstance(text); // Show the dialog. newFragment.show(ft, "dialog"); } void showNotification(boolean custom) { final Resources res = getResources(); final NotificationManager notificationManager = (NotificationManager) getSystemService( NOTIFICATION_SERVICE); Notification.Builder builder = new Notification.Builder(this) .setSmallIcon(R.drawable.ic_stat_notify_example) .setAutoCancel(true) .setTicker(getString(R.string.notification_text)) .setContentIntent(getDialogPendingIntent("Tapped the notification entry.")); if (custom) { // Sets a custom content view for the notification, including an image button. RemoteViews layout = new RemoteViews(getPackageName(), R.layout.notification); layout.setTextViewText(R.id.notification_title, getString(R.string.app_name)); layout.setOnClickPendingIntent(R.id.notification_button, getDialogPendingIntent("Tapped the 'dialog' button in the notification.")); builder.setContent(layout); // Notifications in Android 3.0 now have a standard mechanism for displaying large // bitmaps such as contact avatars. Here, we load an example image and resize it to the // appropriate size for large bitmaps in notifications. Bitmap largeIconTemp = BitmapFactory.decodeResource(res, R.drawable.notification_default_largeicon); Bitmap largeIcon = Bitmap.createScaledBitmap( largeIconTemp, res.getDimensionPixelSize(android.R.dimen.notification_large_icon_width), res.getDimensionPixelSize(android.R.dimen.notification_large_icon_height), false); largeIconTemp.recycle(); builder.setLargeIcon(largeIcon); } else { builder .setNumber(7) // An example number. .setContentTitle(getString(R.string.app_name)) .setContentText(getString(R.string.notification_text)); } notificationManager.notify(NOTIFICATION_DEFAULT, builder.getNotification()); } PendingIntent getDialogPendingIntent(String dialogText) { return PendingIntent.getActivity( this, dialogText.hashCode(), // Otherwise previous PendingIntents with the same // requestCode may be overwritten. new Intent(ACTION_DIALOG) .putExtra(Intent.EXTRA_TEXT, dialogText) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0); } @Override public void onSaveInstanceState (Bundle outState) { super.onSaveInstanceState(outState); outState.putInt("theme", mThemeId); outState.putBoolean("titlesHidden", mTitlesHidden); } /** Implementation for TitlesFragment.OnItemSelectedListener. * When the TitlesFragment receives an onclick event for a list item, * it's passed back to this activity through this method so that we can * deliver it to the ContentFragment in the manner appropriate */ public void onItemSelected(int category, int position) { if (!mDualFragments) { // If showing only the TitlesFragment, start the ContentActivity and // pass it the info about the selected item Intent intent = new Intent(this, ContentActivity.class); intent.putExtra("category", category); intent.putExtra("position", position); intent.putExtra("theme", mThemeId); startActivity(intent); } else { // If showing both fragments, directly update the ContentFragment ContentFragment frag = (ContentFragment) getFragmentManager() .findFragmentById(R.id.content_frag); frag.updateContentAndRecycleBitmap(category, position); } } /** Dialog implementation that shows a simple dialog as a fragment */ public static class MyDialogFragment extends DialogFragment { public static MyDialogFragment newInstance(String title) { MyDialogFragment frag = new MyDialogFragment(); Bundle args = new Bundle(); args.putString("text", title); frag.setArguments(args); return frag; } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { String text = getArguments().getString("text"); return new AlertDialog.Builder(getActivity()) .setTitle("A Dialog of Awesome") .setMessage(text) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { } } ) .create(); } } }
public class CameraActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { int themeId = this.getIntent().getExtras().getInt("theme"); this.setTheme(themeId); super.onCreate(savedInstanceState); setContentView(R.layout.camera_sample); } }
public class CameraFragment extends Fragment { private Preview mPreview; Camera mCamera; int mNumberOfCameras; int mCurrentCamera; // Camera ID currently chosen int mCameraCurrentlyLocked; // Camera ID that's actually acquired // The first rear facing camera int mDefaultCameraId; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Create a container that will hold a SurfaceView for camera previews mPreview = new Preview(this.getActivity()); // Find the total number of cameras available mNumberOfCameras = Camera.getNumberOfCameras(); // Find the ID of the rear-facing ("default") camera CameraInfo cameraInfo = new CameraInfo(); for (int i = 0; i < mNumberOfCameras; i++) { Camera.getCameraInfo(i, cameraInfo); if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) { mCurrentCamera = mDefaultCameraId = i; } } setHasOptionsMenu(mNumberOfCameras > 1); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // Add an up arrow to the "home" button, indicating that the button will go "up" // one activity in the app's Activity heirarchy. // Calls to getActionBar() aren't guaranteed to return the ActionBar when called // from within the Fragment's onCreate method, because the Window's decor hasn't been // initialized yet. Either call for the ActionBar reference in Activity.onCreate() // (after the setContentView(...) call), or in the Fragment's onActivityCreated method. Activity activity = this.getActivity(); ActionBar actionBar = activity.getActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return mPreview; } @Override public void onResume() { super.onResume(); // Use mCurrentCamera to select the camera desired to safely restore // the fragment after the camera has been changed mCamera = Camera.open(mCurrentCamera); mCameraCurrentlyLocked = mCurrentCamera; mPreview.setCamera(mCamera); } @Override public void onPause() { super.onPause(); // Because the Camera object is a shared resource, it's very // important to release it when the activity is paused. if (mCamera != null) { mPreview.setCamera(null); mCamera.release(); mCamera = null; } } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { if (mNumberOfCameras > 1) { // Inflate our menu which can gather user input for switching camera inflater.inflate(R.menu.camera_menu, menu); } else { super.onCreateOptionsMenu(menu, inflater); } } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle item selection switch (item.getItemId()) { case R.id.menu_switch_cam: // Release this camera -> mCameraCurrentlyLocked if (mCamera != null) { mCamera.stopPreview(); mPreview.setCamera(null); mCamera.release(); mCamera = null; } // Acquire the next camera and request Preview to reconfigure // parameters. mCurrentCamera = (mCameraCurrentlyLocked + 1) % mNumberOfCameras; mCamera = Camera.open(mCurrentCamera); mCameraCurrentlyLocked = mCurrentCamera; mPreview.switchCamera(mCamera); // Start the preview mCamera.startPreview(); return true; case android.R.id.home: Intent intent = new Intent(this.getActivity(), MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP); startActivity(intent); return true; default: return super.onOptionsItemSelected(item); } } } // ---------------------------------------------------------------------- /** * A simple wrapper around a Camera and a SurfaceView that renders a centered * preview of the Camera to the surface. We need to center the SurfaceView * because not all devices have cameras that support preview sizes at the same * aspect ratio as the device's display. */ class Preview extends ViewGroup implements SurfaceHolder.Callback { private final String TAG = "Preview"; SurfaceView mSurfaceView; SurfaceHolder mHolder; Size mPreviewSize; List<Size> mSupportedPreviewSizes; Camera mCamera; boolean mSurfaceCreated = false; Preview(Context context) { super(context); mSurfaceView = new SurfaceView(context); addView(mSurfaceView); // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. mHolder = mSurfaceView.getHolder(); mHolder.addCallback(this); mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } public void setCamera(Camera camera) { mCamera = camera; if (mCamera != null) { mSupportedPreviewSizes = mCamera.getParameters() .getSupportedPreviewSizes(); if (mSurfaceCreated) requestLayout(); } } public void switchCamera(Camera camera) { setCamera(camera); try { camera.setPreviewDisplay(mHolder); } catch (IOException exception) { Log.e(TAG, "IOException caused by setPreviewDisplay()", exception); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // We purposely disregard child measurements because act as a // wrapper to a SurfaceView that centers the camera preview instead // of stretching it. final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec); final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec); setMeasuredDimension(width, height); if (mSupportedPreviewSizes != null) { mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height); } if (mCamera != null) { Camera.Parameters parameters = mCamera.getParameters(); parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); mCamera.setParameters(parameters); } } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { if (getChildCount() > 0) { final View child = getChildAt(0); final int width = r - l; final int height = b - t; int previewWidth = width; int previewHeight = height; if (mPreviewSize != null) { previewWidth = mPreviewSize.width; previewHeight = mPreviewSize.height; } // Center the child SurfaceView within the parent. if (width * previewHeight > height * previewWidth) { final int scaledChildWidth = previewWidth * height / previewHeight; child.layout((width - scaledChildWidth) / 2, 0, (width + scaledChildWidth) / 2, height); } else { final int scaledChildHeight = previewHeight * width / previewWidth; child.layout(0, (height - scaledChildHeight) / 2, width, (height + scaledChildHeight) / 2); } } } public void surfaceCreated(SurfaceHolder holder) { // The Surface has been created, acquire the camera and tell it where // to draw. try { if (mCamera != null) { mCamera.setPreviewDisplay(holder); } } catch (IOException exception) { Log.e(TAG, "IOException caused by setPreviewDisplay()", exception); } if (mPreviewSize == null) requestLayout(); mSurfaceCreated = true; } public void surfaceDestroyed(SurfaceHolder holder) { // Surface will be destroyed when we return, so stop the preview. if (mCamera != null) { mCamera.stopPreview(); } } private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) { final double ASPECT_TOLERANCE = 0.1; double targetRatio = (double) w / h; if (sizes == null) return null; Size optimalSize = null; double minDiff = Double.MAX_VALUE; int targetHeight = h; // Try to find an size match aspect ratio and size for (Size size : sizes) { double ratio = (double) size.width / size.height; if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue; if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } // Cannot find the one match the aspect ratio, ignore the requirement if (optimalSize == null) { minDiff = Double.MAX_VALUE; for (Size size : sizes) { if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } } return optimalSize; } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { // Now that the size is known, set up the camera parameters and begin // the preview. Camera.Parameters parameters = mCamera.getParameters(); parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); requestLayout(); mCamera.setParameters(parameters); mCamera.startPreview(); } }
public class ContentActivity extends Activity { private int mThemeId = 0; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Bundle extras = getIntent().getExtras(); if (extras != null) { // The activity theme is the only state data that the activity needs // to restore. All info about the content displayed is managed by the fragment mThemeId = extras.getInt("theme"); } else if (savedInstanceState != null) { // If there's no restore state, get the theme from the intent mThemeId = savedInstanceState.getInt("theme"); } if (mThemeId != 0) { setTheme(mThemeId); } setContentView(R.layout.content_activity); if (extras != null) { // Take the info from the intent and deliver it to the fragment so it can update int category = extras.getInt("category"); int position = extras.getInt("position"); ContentFragment frag = (ContentFragment) getFragmentManager().findFragmentById(R.id.content_frag); frag.updateContentAndRecycleBitmap(category, position); } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt("theme", mThemeId); } }
public class ContentFragment extends Fragment { private View mContentView; private int mCategory = 0; private int mCurPosition = 0; private boolean mSystemUiVisible = true; private boolean mSoloFragment = false; // The bitmap currently used by ImageView private Bitmap mBitmap = null; // Current action mode (contextual action bar, a.k.a. CAB) private ActionMode mCurrentActionMode; /** This is where we initialize the fragment's UI and attach some * event listeners to UI components. */ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mContentView = inflater.inflate(R.layout.content_welcome, null); final ImageView imageView = (ImageView) mContentView.findViewById(R.id.image); mContentView.setDrawingCacheEnabled(false); // Handle drag events when a list item is dragged into the view mContentView.setOnDragListener(new View.OnDragListener() { public boolean onDrag(View view, DragEvent event) { switch (event.getAction()) { case DragEvent.ACTION_DRAG_ENTERED: view.setBackgroundColor( getResources().getColor(R.color.drag_active_color)); break; case DragEvent.ACTION_DRAG_EXITED: view.setBackgroundColor(Color.TRANSPARENT); break; case DragEvent.ACTION_DRAG_STARTED: return processDragStarted(event); case DragEvent.ACTION_DROP: view.setBackgroundColor(Color.TRANSPARENT); return processDrop(event, imageView); } return false; } }); // Show/hide the system status bar when single-clicking a photo. mContentView.setOnClickListener(new OnClickListener() { public void onClick(View view) { if (mCurrentActionMode != null) { // If we're in an action mode, don't toggle the action bar return; } if (mSystemUiVisible) { setSystemUiVisible(false); } else { setSystemUiVisible(true); } } }); // When long-pressing a photo, activate the action mode for selection, showing the // contextual action bar (CAB). mContentView.setOnLongClickListener(new View.OnLongClickListener() { public boolean onLongClick(View view) { if (mCurrentActionMode != null) { return false; } mCurrentActionMode = getActivity().startActionMode( mContentSelectionActionModeCallback); view.setSelected(true); return true; } }); return mContentView; } /** This is where we perform additional setup for the fragment that's either * not related to the fragment's layout or must be done after the layout is drawn. */ @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // Set member variable for whether this fragment is the only one in the activity Fragment listFragment = getFragmentManager().findFragmentById(R.id.titles_frag); mSoloFragment = listFragment == null ? true : false; if (mSoloFragment) { // The fragment is alone, so enable up navigation getActivity().getActionBar().setDisplayHomeAsUpEnabled(true); // Must call in order to get callback to onOptionsItemSelected() setHasOptionsMenu(true); } // Current position and UI visibility should survive screen rotations. if (savedInstanceState != null) { setSystemUiVisible(savedInstanceState.getBoolean("systemUiVisible")); if (mSoloFragment) { // Restoring these members is not necessary when this fragment // is combined with the TitlesFragment, because when the TitlesFragment // is restored, it selects the appropriate item and sends the event // to the updateContentAndRecycleBitmap() method itself mCategory = savedInstanceState.getInt("category"); mCurPosition = savedInstanceState.getInt("listPosition"); updateContentAndRecycleBitmap(mCategory, mCurPosition); } } if (mSoloFragment) { String title = Directory.getCategory(mCategory).getEntry(mCurPosition).getName(); ActionBar bar = getActivity().getActionBar(); bar.setTitle(title); } } @Override public boolean onOptionsItemSelected(MenuItem item) { // This callback is used only when mSoloFragment == true (see onActivityCreated above) switch (item.getItemId()) { case android.R.id.home: // App icon in Action Bar clicked; go up Intent intent = new Intent(getActivity(), MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); // Reuse the existing instance startActivity(intent); return true; default: return super.onOptionsItemSelected(item); } } @Override public void onSaveInstanceState (Bundle outState) { super.onSaveInstanceState(outState); outState.putInt("listPosition", mCurPosition); outState.putInt("category", mCategory); outState.putBoolean("systemUiVisible", mSystemUiVisible); } /** Toggle whether the system UI (status bar / system bar) is visible. * This also toggles the action bar visibility. * @param show True to show the system UI, false to hide it. */ void setSystemUiVisible(boolean show) { mSystemUiVisible = show; Window window = getActivity().getWindow(); WindowManager.LayoutParams winParams = window.getAttributes(); View view = getView(); ActionBar actionBar = getActivity().getActionBar(); if (show) { // Show status bar (remove fullscreen flag) window.setFlags(0, WindowManager.LayoutParams.FLAG_FULLSCREEN); // Show system bar view.setSystemUiVisibility(View.STATUS_BAR_VISIBLE); // Show action bar actionBar.show(); } else { // Add fullscreen flag (hide status bar) window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); // Hide system bar view.setSystemUiVisibility(View.STATUS_BAR_HIDDEN); // Hide action bar actionBar.hide(); } window.setAttributes(winParams); } boolean processDragStarted(DragEvent event) { // Determine whether to continue processing drag and drop based on the // plain text mime type. ClipDescription clipDesc = event.getClipDescription(); if (clipDesc != null) { return clipDesc.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN); } return false; } boolean processDrop(DragEvent event, ImageView imageView) { // Attempt to parse clip data with expected format: category||entry_id. // Ignore event if data does not conform to this format. ClipData data = event.getClipData(); if (data != null) { if (data.getItemCount() > 0) { Item item = data.getItemAt(0); String textData = (String) item.getText(); if (textData != null) { StringTokenizer tokenizer = new StringTokenizer(textData, "||"); if (tokenizer.countTokens() != 2) { return false; } int category = -1; int entryId = -1; try { category = Integer.parseInt(tokenizer.nextToken()); entryId = Integer.parseInt(tokenizer.nextToken()); } catch (NumberFormatException exception) { return false; } updateContentAndRecycleBitmap(category, entryId); // Update list fragment with selected entry. TitlesFragment titlesFrag = (TitlesFragment) getFragmentManager().findFragmentById(R.id.titles_frag); titlesFrag.selectPosition(entryId); return true; } } } return false; } /** * Sets the current image visible. * @param category Index position of the image category * @param position Index position of the image */ void updateContentAndRecycleBitmap(int category, int position) { mCategory = category; mCurPosition = position; if (mCurrentActionMode != null) { mCurrentActionMode.finish(); } if (mBitmap != null) { // This is an advanced call and should be used if you // are working with a lot of bitmaps. The bitmap is dead // after this call. mBitmap.recycle(); } // Get the bitmap that needs to be drawn and update the ImageView mBitmap = Directory.getCategory(category).getEntry(position) .getBitmap(getResources()); ((ImageView) getView().findViewById(R.id.image)).setImageBitmap(mBitmap); } /** Share the currently selected photo using an AsyncTask to compress the image * and then invoke the appropriate share intent. */ void shareCurrentPhoto() { File externalCacheDir = getActivity().getExternalCacheDir(); if (externalCacheDir == null) { Toast.makeText(getActivity(), "Error writing to USB/external storage.", Toast.LENGTH_SHORT).show(); return; } // Prevent media scanning of the cache directory. final File noMediaFile = new File(externalCacheDir, ".nomedia"); try { noMediaFile.createNewFile(); } catch (IOException e) { } // Write the bitmap to temporary storage in the external storage directory (e.g. SD card). // We perform the actual disk write operations on a separate thread using the // {@link AsyncTask} class, thus avoiding the possibility of stalling the main (UI) thread. final File tempFile = new File(externalCacheDir, "tempfile.jpg"); new AsyncTask<Void, Void, Boolean>() { /** * Compress and write the bitmap to disk on a separate thread. * @return TRUE if the write was successful, FALSE otherwise. */ @Override protected Boolean doInBackground(Void... voids) { try { FileOutputStream fo = new FileOutputStream(tempFile, false); if (!mBitmap.compress(Bitmap.CompressFormat.JPEG, 60, fo)) { Toast.makeText(getActivity(), "Error writing bitmap data.", Toast.LENGTH_SHORT).show(); return Boolean.FALSE; } return Boolean.TRUE; } catch (FileNotFoundException e) { Toast.makeText(getActivity(), "Error writing to USB/external storage.", Toast.LENGTH_SHORT).show(); return Boolean.FALSE; } } /** * After doInBackground completes (either successfully or in failure), we invoke an * intent to share the photo. This code is run on the main (UI) thread. */ @Override protected void onPostExecute(Boolean result) { if (result != Boolean.TRUE) { return; } Intent shareIntent = new Intent(Intent.ACTION_SEND); shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(tempFile)); shareIntent.setType("image/jpeg"); startActivity(Intent.createChooser(shareIntent, "Share photo")); } }.execute(); } /** * The callback for the 'photo selected' {@link ActionMode}. In this action mode, we can * provide contextual actions for the selected photo. We currently only provide the 'share' * action, but we could also add clipboard functions such as cut/copy/paste here as well. */ private ActionMode.Callback mContentSelectionActionModeCallback = new ActionMode.Callback() { public boolean onCreateActionMode(ActionMode actionMode, Menu menu) { actionMode.setTitle(R.string.photo_selection_cab_title); MenuInflater inflater = getActivity().getMenuInflater(); inflater.inflate(R.menu.photo_context_menu, menu); return true; } public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) { return false; } public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) { switch (menuItem.getItemId()) { case R.id.menu_share: shareCurrentPhoto(); actionMode.finish(); return true; } return false; } public void onDestroyActionMode(ActionMode actionMode) { mContentView.setSelected(false); mCurrentActionMode = null; } }; }
public class Directory { private static DirectoryCategory[] mCategories; public static void initializeDirectory() { mCategories = new DirectoryCategory[] { new DirectoryCategory("Balloons", new DirectoryEntry[] { new DirectoryEntry("Red Balloon", R.drawable.red_balloon), new DirectoryEntry("Green Balloon", R.drawable.green_balloon), new DirectoryEntry("Blue Balloon", R.drawable.blue_balloon)}), new DirectoryCategory("Bikes", new DirectoryEntry[] { new DirectoryEntry("Old school huffy", R.drawable.blue_bike), new DirectoryEntry("New Bikes", R.drawable.rainbow_bike), new DirectoryEntry("Chrome Fast", R.drawable.chrome_wheel)}), new DirectoryCategory("Androids", new DirectoryEntry[] { new DirectoryEntry("Steampunk Android", R.drawable.punk_droid), new DirectoryEntry("Stargazing Android", R.drawable.stargazer_droid), new DirectoryEntry("Big Android", R.drawable.big_droid) }), new DirectoryCategory("Pastries", new DirectoryEntry[] { new DirectoryEntry("Cupcake", R.drawable.cupcake), new DirectoryEntry("Donut", R.drawable.donut), new DirectoryEntry("Eclair", R.drawable.eclair), new DirectoryEntry("Froyo", R.drawable.froyo), }), }; } public static int getCategoryCount() { return mCategories.length; } public static DirectoryCategory getCategory(int i) { return mCategories[i]; } }
public class DirectoryCategory { private String name; private DirectoryEntry[] entries; public DirectoryCategory(String name, DirectoryEntry[] entries) { this.name = name; this.entries = entries; } public String getName() { return name; } public int getEntryCount() { return entries.length; } public DirectoryEntry getEntry(int i) { return entries[i]; } }
public class DirectoryEntry { private String name; private int resID; public DirectoryEntry(String name, int resID) { this.name = name; this.resID = resID; } public String getName() { return name; } public Drawable getDrawable(Resources res) { return res.getDrawable(resID); } public Bitmap getBitmap(Resources res) { return BitmapFactory.decodeResource(res, resID); } }
public class FitCenterFrameLayout extends ViewGroup { public FitCenterFrameLayout(Context context) { super(context); } public FitCenterFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // We purposely disregard child measurements. final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec); final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec); setMeasuredDimension(width, height); int childWidthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.UNSPECIFIED); int childHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.UNSPECIFIED); int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { getChildAt(i).measure(childWidthSpec, childHeightSpec); } } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int childCount = getChildCount(); final int parentLeft = getPaddingLeft(); final int parentTop = getPaddingTop(); final int parentRight = r - l - getPaddingRight(); final int parentBottom = b - t - getPaddingBottom(); final int parentWidth = parentRight - parentLeft; final int parentHeight = parentBottom - parentTop; int unpaddedWidth, unpaddedHeight, parentUnpaddedWidth, parentUnpaddedHeight; int childPaddingLeft, childPaddingTop, childPaddingRight, childPaddingBottom; for (int i = 0; i < childCount; i++) { final View child = getChildAt(i); if (child.getVisibility() == GONE) { continue; } // Fit and center the child within the parent. Make sure not to consider padding // as part of the child's aspect ratio. childPaddingLeft = child.getPaddingLeft(); childPaddingTop = child.getPaddingTop(); childPaddingRight = child.getPaddingRight(); childPaddingBottom = child.getPaddingBottom(); unpaddedWidth = child.getMeasuredWidth() - childPaddingLeft - childPaddingRight; unpaddedHeight = child.getMeasuredHeight() - childPaddingTop - childPaddingBottom; parentUnpaddedWidth = parentWidth - childPaddingLeft - childPaddingRight; parentUnpaddedHeight = parentHeight - childPaddingTop - childPaddingBottom; if (parentUnpaddedWidth * unpaddedHeight > parentUnpaddedHeight * unpaddedWidth) { // The child view should be left/right letterboxed. final int scaledChildWidth = unpaddedWidth * parentUnpaddedHeight / unpaddedHeight + childPaddingLeft + childPaddingRight; child.layout( parentLeft + (parentWidth - scaledChildWidth) / 2, parentTop, parentRight - (parentWidth - scaledChildWidth) / 2, parentBottom); } else { // The child view should be top/bottom letterboxed. final int scaledChildHeight = unpaddedHeight * parentUnpaddedWidth / unpaddedWidth + childPaddingTop + childPaddingBottom; child.layout( parentLeft, parentTop + (parentHeight - scaledChildHeight) / 2, parentRight, parentTop + (parentHeight + scaledChildHeight) / 2); } } } }
/** * 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) { } }
相关文章推荐
- [翻译]GooglePlayServicesUtil Google服务工具类
- Django URLconf
- USACO 3.2 Spinning Wheels (spin)
- USACO 3.2 Stringsobits (kimbits)
- USACO 3.2 Factorials (fact4)
- USACO 3.1 Stamps (stamps)
- Golang 学习1:开发环境
- Image Analysis, Classification, and Change Detection in Remote Sensing: With Algorithms for ENVI/IDL, Second Edition
- MtGox破产,对比特币是致命一击
- pymongo
- Django初级手册4-表单与通用视图
- Django初级手册3-视图层与URL配置
- Django初级手册2-管理界面的使用及定制
- A simple Kalman Filtre Algorithme
- 【ADT】亲测、有图goagent解决ADT下载过慢的问题
- 关于goroutine和channel的使用和个人见解
- 2014.2.25 改进型冒泡排序 improved bubble sort algorithm
- 2014.2.24 冒泡排序法 Bubble Sort algorithm
- Dining poj 3281 拆点+
- 使用Django从事web开发需要具备的知识。