Java tutorial
/* * ================================================================================= * Copyright (C) 2013 Martin Albedinsky [Wolf-ITechnologies] * ================================================================================= * Licensed under the Apache License, Version 2.0 or later (further "License" only); * --------------------------------------------------------------------------------- * You may use this file only in compliance with the License. More details and copy * of this License you may obtain at * * http://www.apache.org/licenses/LICENSE-2.0 * * You can redistribute, modify or publish any part of the code written in this * file but as it is described in the License, the software distributed under the * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES or CONDITIONS OF * ANY KIND. * * See the License for the specific language governing permissions and limitations * under the License. * ================================================================================= */ package com.wit.and.dialog; import android.app.Activity; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.os.Bundle; import android.os.Parcel; import android.support.v4.app.Fragment; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.BaseAdapter; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.TextView; import com.wit.and.dialog.manage.DialogOptions; import com.wit.and.style.styler.WidgetStyler; /** * <h4>Class Overview</h4> * <p> * Dialog contains {@link ListView} in it's body view. * </p> * <p> * Can be used to show some listed items in the dialog (like options list or * online contacts in some messenger app). * </p> * <h3>Dialog styling:</h3> * <p> * This dialog implementation parses its style from main <b>dialogTheme</b> * where <b>listDialogStyle</b> is obtained to apply styles to specific * view elements for list dialog. * </p> * * @author Martin Albedinsky * @see Dialog */ public class ListDialog extends Dialog implements IListDialog, OnItemClickListener, OnItemLongClickListener, OnItemSelectedListener { /** * Constants ============================= */ /** * <p> * </p> */ public static final int DEFAULT_RES = -0x01; /** * Indicates if logging for user output trough log-cat is enabled. */ // private static final boolean USER_LOG = true; /** * Bundle identifiers. */ /** */ protected static final String BUNDLE_ADAPTER_ID = "com.wit.and.dialog.ListDialog.Bundle.Adapter.ID"; protected static final String BUNDLE_LIST_VIEW_RES = "com.wit.and.dialog.ListDialog.Bundle.ListView.Res"; protected static final String BUNDLE_EMPTY_VIEW_RES = "com.wit.and.dialog.ListDialog.Bundle.EmptyView.Res"; /** * Log TAG. */ private static final String TAG = ListDialog.class.getSimpleName(); /** * Indicates if debug private output trough log-cat is enabled. */ private static final boolean DEBUG = false; /** * Enums ================================= */ /** * Static members ======================== */ /** * Members =============================== */ /** * Widget stylers. */ /** */ private final WidgetStyler.ListViewStyler LIST_STYLER = new WidgetStyler.ListViewStyler(0); private final WidgetStyler.TextViewStyler TEXT_STYLER = new WidgetStyler.TextViewStyler(0); /** * Base adapter to fill list view with items. */ private BaseAdapter mAdapter; /** * List view for items. */ private ListView mListView; /** * Text view to show text when the list view is empty. */ private TextView mEmptyTextView; /** * Listeners ----------------------------- */ private OnListListener iListener = null; private OnListListener iParentListener = null; /** * Arrays -------------------------------- */ /** * Booleans ------------------------------ */ /** * Constructors ========================== */ /** * Methods =============================== */ /** * Public -------------------------------- */ /** * <p> * Creates new instance of list dialog fragment. * </p> * * @return New instance of list dialog fragment. */ public static ListDialog newInstance() { // Return new instance of this dialog. return new ListDialog(); } /** * <p> * Creates new instance of list dialog fragment. * </p> * * @param listOptions Specific dialog options for list dialog. * @return New instance of list dialog fragment. */ public static ListDialog newInstance(ListOptions listOptions) { final ListDialog dialog = new ListDialog(); dialog.setCancelable(listOptions.isCancelable()); // Set up dialog arguments. dialog.setArguments(createArguments(listOptions)); return dialog; } /** */ @Override public void onActivityCreated(Bundle bundle) { super.onActivityCreated(bundle); Activity activity = this.getActivity(); Fragment fragment = this.getFragmentManager().findFragmentByTag(this.getParentFragmentTag()); // Check if some of the parents implements our listener. if (fragment != null && fragment instanceof OnListListener) { this.iParentListener = (OnListListener) fragment; } else if (activity != null && activity instanceof OnListListener) { this.iParentListener = (OnListListener) activity; } if (mAdapter == null) { // Obtain adapter. this.setAdapter(this.getParentAdapter(getOptions().getAdapterID())); } } /** */ @Override public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) { if (DEBUG) Log.d(TAG, "onItemSelected(" + position + ")"); if (this.iListener != null) { this.iListener.onListDialogItemSelected(this, adapterView, view, position, id); } if (this.iParentListener != null) { this.iParentListener.onListDialogItemSelected(this, adapterView, view, position, id); } } /** */ @Override public void onNothingSelected(AdapterView<?> adapterView) { if (DEBUG) Log.d(TAG, "onNothingSelected()"); if (this.iListener != null) { this.iListener.onListDialogNothingSelected(this, adapterView); } if (this.iParentListener != null) { this.iParentListener.onListDialogNothingSelected(this, adapterView); } } /** */ @Override public boolean onItemLongClick(AdapterView<?> adapterView, View view, int position, long id) { if (DEBUG) Log.d(TAG, "onItemLongClick(" + position + ")"); boolean success = false; if (this.iListener != null) { success = this.iListener.onListDialogItemLongClick(this, adapterView, view, position, id); } if (this.iParentListener != null) { success = this.iParentListener.onListDialogItemLongClick(this, adapterView, view, position, id); } return success; } /** */ @Override public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { if (DEBUG) Log.d(TAG, "onItemClick(" + position + ")"); if (iListener != null) { iListener.onListDialogItemClick(this, adapterView, view, position, id); } if (iParentListener != null) { iParentListener.onListDialogItemClick(this, adapterView, view, position, id); } } /** * Getters + Setters --------------------- */ /** */ @Override public ListOptions getOptions() { return (ListOptions) super.getOptions(); } /** * <p> * Sets adapter for the list view of this list dialog. * </p> * * @param adapter List view adapter. */ public void setAdapter(BaseAdapter adapter) { this.mAdapter = adapter; // Refresh list view. if (mListView != null) { mListView.setAdapter(adapter); } } /** * <p> * Returns current dialog list view adapter. * </p> */ @Override public BaseAdapter getAdapter() { return mAdapter; } /** * <p> * Sets listener for this list dialog to listen for basic callback from the * list view. * </p> * * @param listener ListDialog listener. * @see com.wit.and.dialog.IListDialog.OnListListener */ public void setOnListDialogListener(OnListListener listener) { this.iListener = listener; } /** * <p> * Returns dialog list view or <code>null</code> if there is no list view currently inflated. * </p> */ @Override public ListView getListView() { return mListView; } /** * Protected ----------------------------- */ /** */ @Override protected View onCreateBodyView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final Context context = inflater.getContext(); // There will be default empty view behind the list view in relative layout. RelativeLayout layout = new RelativeLayout(context); if (container instanceof LinearLayout) { // Apply valid linear layout params to fit with list view just left space in the dialog main view. LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, 0); layoutParams.weight = 1; layout.setLayoutParams(layoutParams); } else { // Apply neutral layout params. layout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); } layout.setGravity(Gravity.CENTER); // Do not allow to apply style to body view. // layout.setId(R.id.Dialog_Layout_Body); // Create empty view and insert it into body layout behind the list view. View emptyView = onCreateEmptyView(inflater, container, savedInstanceState); if (emptyView != null) { layout.addView(emptyView); } // Create list view and insert it into body layout. ListView listView = onCreateListView(inflater, layout, savedInstanceState); if (listView != null) { layout.addView(listView); } return layout; } /** * <p> * Invoked to create dialog list view. * </p> * <p> * Here is the best place to provide custom list view. * </p> * * @param inflater Layout inflater. * @param container Layout created in the {@link #onCreateBodyView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)} * @param savedInstanceState Saved dialog state. * @return Created dialog list view. */ protected ListView onCreateListView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { ListView listView; final ListOptions options = getOptions(); if (options.getListViewRes() != DEFAULT_RES) { // Inflate custom list view. listView = (ListView) inflater.inflate(options.getListViewRes(), null, false); } else { // Create default list view. listView = new ListView(inflater.getContext(), null, android.R.attr.listViewStyle); listView.setId(R.id.And_Dialog_ListView); RelativeLayout.LayoutParams listViewParams = new RelativeLayout.LayoutParams( RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT); listViewParams.addRule(RelativeLayout.CENTER_IN_PARENT); listView.setLayoutParams(listViewParams); } return listView; } /** * <p> * Invoked to create dialog empty view for list view. * </p> * <p> * Here is the best place to provide custom empty view. * </p> * * @param inflater Layout inflater. * @param container Layout created in the {@link #onCreateBodyView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)} * @param savedInstanceState Saved dialog state. * @return Created empty view. */ protected View onCreateEmptyView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View emptyView; final ListOptions options = getOptions(); if (options.getEmptyViewRes() != DEFAULT_RES) { // Inflate custom empty view. emptyView = inflater.inflate(options.getEmptyViewRes(), null, false); } else { // Create default empty text view. TextView textView = new TextView(inflater.getContext()); textView.setId(android.R.id.empty); textView.setGravity(Gravity.CENTER); textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); textView.setVisibility(View.GONE); emptyView = textView; } return emptyView; } /** */ @Override protected void onInitViews(View dialogView) { super.onInitViews(dialogView); // Initialize list view. this.mListView = (ListView) findViewByID(R.id.And_Dialog_ListView); mListView.setEmptyView(mEmptyTextView); // Check for default empty text view. View empty = findViewByID(android.R.id.empty); if (empty != null && empty instanceof TextView) { this.mEmptyTextView = (TextView) empty; } // Set adapter. if (mListView != null && mAdapter != null) { mListView.setAdapter(mAdapter); } // Set up list view. if (mListView != null) { mListView.setOnItemClickListener(this); mListView.setOnItemLongClickListener(this); mListView.setOnItemSelectedListener(this); mListView.setEmptyView(empty); } } /** */ @Override protected void onBindDialog(View dialogView, Bundle bundle) { super.onBindDialog(dialogView, bundle); if (mEmptyTextView != null) { mEmptyTextView.setText(this.getOptions().getMessage()); } } /** */ @Override protected void onStyleDialog(View dialogView, TypedArray parsedArray) { final Context context = getActivity(); final int listDialogStyle = parsedArray.getResourceId(R.styleable.And_Theme_Dialog_listDialogStyle, R.style.And_Dialog_ListDialog); final TypedArray dialogArray = context.obtainStyledAttributes(listDialogStyle, R.styleable.And_Theme_Dialog_ListDialog); if (dialogArray != null) { final int n = dialogArray.getIndexCount(); for (int i = 0; i < n; i++) { int attr = dialogArray.getIndex(i); /** * Obtain list dialog sub-dialog style. */ if (attr == R.styleable.And_Theme_Dialog_ListDialog_dialogStyle) { final int dialogStyle = dialogArray.getResourceId(attr, R.style.And_Dialog_Dialog); /** * Let super to process list dialog sub-dialog style. */ super.onStyleDialog(dialogView, dialogStyle); // Set up empty text view style. if (mEmptyTextView != null) { final TypedArray bodyArray = context.obtainStyledAttributes(dialogStyle, new int[] { R.attr.dialogBodyStyle }); if (bodyArray != null) { final int bodyStyle = bodyArray.getResourceId(0, R.style.And_Dialog_Body); // Apply body style to get some padding. TEXT_STYLER.performStyling(bodyStyle, mEmptyTextView); final TypedArray textArray = context.obtainStyledAttributes(bodyStyle, new int[] { android.R.attr.textViewStyle }); if (textArray != null) { // Apply message text style. TEXT_STYLER.performStyling(textArray.getResourceId(0, R.style.And_Dialog_TextView), mEmptyTextView); textArray.recycle(); } bodyArray.recycle(); } } } /** * Set up list dialog list view style. */ else if (attr == R.styleable.And_Theme_Dialog_ListDialog_android_listViewStyle) { if (mListView != null) { LIST_STYLER.performStyling(dialogArray.getResourceId(attr, R.style.And_Dialog_ListView), mListView); } } } dialogArray.recycle(); } } /** * Private ------------------------------- */ /** * Checks if the parent activity/fragment implements adapter provider. If * yes returns the provided adapter. * * @param adapterID Id of adapter to obtain. * @return Adapter for list view or <code>null</code> if parent isnt' adapter provider. */ private BaseAdapter getParentAdapter(int adapterID) { BaseAdapter adapter = null; Activity activity = this.getActivity(); Fragment fragment = this.getFragmentManager().findFragmentByTag(this.getParentFragmentTag()); if (fragment != null && fragment instanceof ListDialogAdapterProvider) { adapter = ((ListDialogAdapterProvider) fragment).onGetListDialogAdapter(getDialogID(), adapterID); } else if (activity != null && activity instanceof ListDialogAdapterProvider) { adapter = ((ListDialogAdapterProvider) activity).onGetListDialogAdapter(getDialogID(), adapterID); } return adapter; } /** * Abstract methods ---------------------- */ /** * Inner classes ========================= */ /** * <h4>Class Overview</h4> * <p> * Specific dialog options for {@link ListDialog}. * </p> * * @author Martin Albedinsky * @see ListDialog * @see com.wit.and.dialog.manage.DialogOptions */ public static class ListOptions extends DialogOptions<ListOptions> { /** * Members =============================== */ /** * Id of the adapter to pass to the list dialog. */ int adapterID = -1; /** * Resource for list view layout. */ int listViewRes = ListDialog.DEFAULT_RES; /** * Resource for empty view layout. */ int emptyViewRes = ListDialog.DEFAULT_RES; /** * Constructors ========================== */ /** * <p> * Same as {@link com.wit.and.dialog.manage.DialogOptions#DialogOptions()}. * </p> */ public ListOptions() { super(); } /** * <p> * Same as {@link com.wit.and.dialog.manage.DialogOptions#DialogOptions(android.content.res.Resources)}. * </p> * * @param resources */ public ListOptions(Resources resources) { super(resources); } /** * <p> * Same as {@link com.wit.and.dialog.manage.DialogOptions#DialogOptions(android.os.Parcel)}. * </p> * * @param input */ protected ListOptions(Parcel input) { super(input); this.adapterID = input.readInt(); this.listViewRes = input.readInt(); this.emptyViewRes = input.readInt(); } /** * Methods =============================== */ /** * Public -------------------------------- */ /** */ @Override public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); dest.writeInt(adapterID); dest.writeInt(listViewRes); dest.writeInt(emptyViewRes); } /** * Getters + Setters --------------------- */ /** * <p> * Sets the id of adapter for list dialog. * </p> * * @param id Id of adapter. * @return This options. */ public ListOptions adapterID(int id) { this.adapterID = id; return this; } public int getAdapterID() { return adapterID; } /** * <p> * Sets resource for layout which will represent * empty view for list dialog's list view. * </p> * * @param emptyLayoutRes Layout resource. * @return This options. */ public ListOptions emptyView(int emptyLayoutRes) { this.emptyViewRes = emptyLayoutRes; return this; } /** * <p> * </p> * * @return */ public int getEmptyViewRes() { return emptyViewRes; } /** * <p> * Sets resource for layout with custom list view. * </p> * * @param listViewLayoutRes Layout resource. * @return This options. */ public ListOptions listView(int listViewLayoutRes) { this.listViewRes = listViewLayoutRes; return this; } /** * <p> * </p> * * @return */ public int getListViewRes() { return listViewRes; } } /** * Interface ============================= */ }