О том как написать Хеллоу Ворлд в интернете полным полно, так что я решил рассказать о более интересных вещах. Официальное приложение Twitter для Android использует паттерны и возможности графического интерфейса появившиеся в последних версиях sdk, такие как Dashboard, Search Bar, QuickAction и Action Bar. Диалог QuickAction является одной из самых интересных новинок, он отображает контекстное действия для данного элемента ListView. Этот диалог используется также в приложении контактов, начиная с версии 2.0
Диалог QuickAction не входит в стандартный sdk, поэтому мы попытаем создать его самим. Изначально у меня не было никаких идей, оставалось только скачать исходники приложения Contacts и посмотреть, как это делается, благо android это open source. Копаясь в исходниках я заметил, что там используются приватные API вызовы(com.android.internal.policy.PolicyManager), которые недоступны в стандартном sdk.Немного поразмыслив я нашел выход, построенный на основе исходников Сontacts. Вот исходники самого главного класс, который реализует в себе всплывающий диалог. Для использования кастомного диалого просто наследуемся от него.
Теперь нам нужно написать класс, который будет являтся конкретным Action.
Теперь перейдем к самому интересному созданию самого диалогового окна.
Нам надо будет создать класс, который наследуется от CustomPopupWindow
Пусть вас не пугает код, использовать его очень просто, теперь попробуем использовать весь этот код.
Не буду приводить весь код, тут все предельно просто.
P.S. используйте в своих приложениях.
P.S.S Оригинал статьи лежит в моем блоге
Диалог QuickAction не входит в стандартный sdk, поэтому мы попытаем создать его самим. Изначально у меня не было никаких идей, оставалось только скачать исходники приложения Contacts и посмотреть, как это делается, благо android это open source. Копаясь в исходниках я заметил, что там используются приватные API вызовы(com.android.internal.policy.PolicyManager), которые недоступны в стандартном sdk.Немного поразмыслив я нашел выход, построенный на основе исходников Сontacts. Вот исходники самого главного класс, который реализует в себе всплывающий диалог. Для использования кастомного диалого просто наследуемся от него.
- package az.mecid.popup.
-
- import android.content.Context;
-
- import android.graphics.Rect;
- import android.graphics.drawable.BitmapDrawable;
- import android.graphics.drawable.Drawable;
-
- import android.view.Gravity;
- import android.view.LayoutInflater;
- import android.view.MotionEvent;
- import android.view.View;
- import android.view.View.OnTouchListener;
- import android.view.ViewGroup.LayoutParams;
- import android.view.WindowManager;
-
- import android.widget.PopupWindow;
-
- public class CustomPopupWindow {
- protected final View anchor;
- protected final PopupWindow window;
- private View root;
- private Drawable background = null;
- protected final WindowManager windowManager;
-
- public CustomPopupWindow(View anchor) {
- this.anchor = anchor;
- this.window = new PopupWindow(anchor.getContext());
-
- // Если происходит прикосновение за пределами диалогового окна,то окно закрывается
- window.setTouchInterceptor(new OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
- CustomPopupWindow.this.window.dismiss();
-
- return true;
- }
-
- return false;
- }
- });
-
- windowManager = (WindowManager) anchor.getContext().getSystemService(Context.WINDOW_SERVICE);
-
- onCreate();
- }
-
- protected void onCreate() {}
-
-
- protected void onShow() {}
-
- protected void preShow() {
- if (root == null) {
- throw new IllegalStateException("error");
- }
-
- onShow();
-
- if (background == null) {
- window.setBackgroundDrawable(new BitmapDrawable());
- } else {
- window.setBackgroundDrawable(background);
- }
-
- window.setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
- window.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
- window.setTouchable(true);
- window.setFocusable(true);
- window.setOutsideTouchable(true);
-
- window.setContentView(root);
- }
-
- public void setBackgroundDrawable(Drawable background) {
- this.background = background;
- }
-
- public void setContentView(View root) {
- this.root = root;
-
- window.setContentView(root);
- }
-
- public void setContentView(int layoutResID) {
- LayoutInflater inflator =
- (LayoutInflater) anchor.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
- setContentView(inflator.inflate(layoutResID, null));
- }
-
-
- public void setOnDismissListener(PopupWindow.OnDismissListener listener) {
- window.setOnDismissListener(listener);
- }
-
-
- public void showDropDown() {
- showDropDown(0, 0);
- }
-
- public void showDropDown(int xOffset, int yOffset) {
- preShow();
-
- window.setAnimationStyle(R.style.Animations_PopDownMenu);
-
- window.showAsDropDown(anchor, xOffset, yOffset);
- }
-
- public void showLikeQuickAction() {
- showLikeQuickAction(0, 0);
- }
-
- public void showLikeQuickAction(int xOffset, int yOffset) {
- preShow();
-
- window.setAnimationStyle(R.style.Animations_PopUpMenu_Center);
-
- int[] location = new int[2];
- anchor.getLocationOnScreen(location);
-
- Rect anchorRect =
- new Rect(location[0], location[1], location[0] + anchor.getWidth(), location[1]
- + anchor.getHeight());
-
- root.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
- root.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
-
- int rootWidth = root.getMeasuredWidth();
- int rootHeight = root.getMeasuredHeight();
-
- int screenWidth = windowManager.getDefaultDisplay().getWidth();
-
- int xPos = ((screenWidth - rootWidth) / 2) + xOffset;
- int yPos = anchorRect.top - rootHeight + yOffset;
-
-
- if (rootHeight > anchorRect.top) {
- yPos = anchorRect.bottom + yOffset;
-
- window.setAnimationStyle(R.style.Animations_PopDownMenu_Center);
- }
-
- window.showAtLocation(anchor, Gravity.NO_GRAVITY, xPos, yPos);
- }
-
- public void dismiss() {
- window.dismiss();
- }
- }
* This source code was highlighted with Source Code Highlighter
.
Теперь нам нужно написать класс, который будет являтся конкретным Action.
- package az.mecid.popups;
-
- import android.graphics.drawable.Drawable;
- import android.view.View.OnClickListener;
-
- public class ActionItem {
- private Drawable icon;
- private String title;
- private OnClickListener listener;
-
- public ActionItem() {}
-
- public ActionItem(Drawable icon) {
- this.icon = icon;
- }
-
- public void setTitle(String title) {
- this.title = title;
- }
-
- public String getTitle() {
- return this.title;
- }
-
- public void setIcon(Drawable icon) {
- this.icon = icon;
- }
-
- public Drawable getIcon() {
- return this.icon;
- }
-
-
- public void setOnClickListener(OnClickListener listener) {
- this.listener = listener;
- }
-
- public OnClickListener getListener() {
- return this.listener;
- }
- }
* This source code was highlighted with Source Code Highlighter
.
Теперь перейдем к самому интересному созданию самого диалогового окна.
Нам надо будет создать класс, который наследуется от CustomPopupWindow
- package az.mecid.popups;
-
- import android.content.Context;
-
- import android.graphics.Rect;
- import android.graphics.drawable.Drawable;
-
- import android.widget.ImageView;
- import android.widget.TextView;
- import android.widget.LinearLayout;
- import android.widget.ScrollView;
-
- import android.view.Gravity;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.view.ViewGroup.LayoutParams;
- import android.view.ViewGroup;
-
- import java.util.ArrayList;
-
- public class QuickAction extends CustomPopupWindow {
- private final View root;
- private final ImageView mArrowUp;
- private final ImageView mArrowDown;
- private final LayoutInflater inflater;
- private final Context context;
-
- protected static final int ANIM_GROW_FROM_LEFT = 1;
- protected static final int ANIM_GROW_FROM_RIGHT = 2;
- protected static final int ANIM_GROW_FROM_CENTER = 3;
- protected static final int ANIM_REFLECT = 4;
- protected static final int ANIM_AUTO = 5;
-
- private int animStyle;
- private ViewGroup mTrack;
- private ScrollView scroller;
- private ArrayList<ActionItem> actionList;
-
- public QuickAction(View anchor) {
- super(anchor);
-
- actionList = new ArrayList<ActionItem>();
- context = anchor.getContext();
- inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
- root = (ViewGroup) inflater.inflate(R.layout.popup, null);
-
- mArrowDown = (ImageView) root.findViewById(R.id.arrow_down);
- mArrowUp = (ImageView) root.findViewById(R.id.arrow_up);
-
- setContentView(root);
-
- mTrack = (ViewGroup) root.findViewById(R.id.tracks);
- scroller = (ScrollView) root.findViewById(R.id.scroller);
- animStyle = ANIM_AUTO;
- }
-
- public void setAnimStyle(int animStyle) {
- this.animStyle = animStyle;
- }
-
- public void addActionItem(ActionItem action) {
- actionList.add(action);
- }
-
- public void show () {
- preShow();
-
- int xPos, yPos;
-
- int[] location = new int[2];
-
- anchor.getLocationOnScreen(location);
-
- Rect anchorRect = new Rect(location[0], location[1], location[0] + anchor.getWidth(), location[1]
- + anchor.getHeight());
-
- createActionList();
-
- root.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
- root.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
-
- int rootHeight = root.getMeasuredHeight();
- int rootWidth = root.getMeasuredWidth();
-
- int screenWidth = windowManager.getDefaultDisplay().getWidth();
- int screenHeight = windowManager.getDefaultDisplay().getHeight();
-
- if ((anchorRect.left + rootWidth) > screenWidth) {
- xPos = anchorRect.left - (rootWidth-anchor.getWidth());
- } else {
- if (anchor.getWidth() > rootWidth) {
- xPos = anchorRect.centerX() - (rootWidth/2);
- } else {
- xPos = anchorRect.left;
- }
- }
-
- int dyTop = anchorRect.top;
- int dyBottom = screenHeight - anchorRect.bottom;
-
- boolean onTop = (dyTop > dyBottom) ? true : false;
-
- if (onTop) {
- if (rootHeight > dyTop) {
- yPos = 15;
- LayoutParams l = scroller.getLayoutParams();
- l.height = dyTop - anchor.getHeight();
- } else {
- yPos = anchorRect.top - rootHeight;
- }
- } else {
- yPos = anchorRect.bottom;
-
- if (rootHeight > dyBottom) {
- LayoutParams l = scroller.getLayoutParams();
- l.height = dyBottom;
- }
- }
-
- showArrow(((onTop) ? R.id.arrow_down : R.id.arrow_up), anchorRect.centerX()-xPos);
-
- setAnimationStyle(screenWidth, anchorRect.centerX(), onTop);
-
- window.showAtLocation(anchor, Gravity.NO_GRAVITY, xPos, yPos);
- }
-
- private void setAnimationStyle(int screenWidth, int requestedX, boolean onTop) {
- int arrowPos = requestedX - mArrowUp.getMeasuredWidth()/2;
-
- switch (animStyle) {
- case ANIM_GROW_FROM_LEFT:
- window.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Left : R.style.Animations_PopDownMenu_Left);
- break;
-
- case ANIM_GROW_FROM_RIGHT:
- window.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Right : R.style.Animations_PopDownMenu_Right);
- break;
-
- case ANIM_GROW_FROM_CENTER:
- window.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Center : R.style.Animations_PopDownMenu_Center);
- break;
-
- case ANIM_REFLECT:
- window.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Reflect : R.style.Animations_PopDownMenu_Reflect);
- break;
-
- case ANIM_AUTO:
- if (arrowPos <= screenWidth/4) {
- window.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Left : R.style.Animations_PopDownMenu_Left);
- } else if (arrowPos > screenWidth/4 && arrowPos < 3 * (screenWidth/4)) {
- window.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Center : R.style.Animations_PopDownMenu_Center);
- } else {
- window.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Right : R.style.Animations_PopDownMenu_Right);
- }
-
- break;
- }
- }
-
- private void createActionList() {
- View view;
- String title;
- Drawable icon;
- OnClickListener listener;
-
- for (int i = 0; i < actionList.size(); i++) {
- title = actionList.get(i).getTitle();
- icon = actionList.get(i).getIcon();
- listener = actionList.get(i).getListener();
-
- view = getActionItem(title, icon, listener);
-
- view.setFocusable(true);
- view.setClickable(true);
-
- mTrack.addView(view);
- }
- }
-
- private View getActionItem(String title, Drawable icon, OnClickListener listener) {
- LinearLayout container = (LinearLayout) inflater.inflate(R.layout.action_item, null);
-
- ImageView img = (ImageView) container.findViewById(R.id.icon);
- TextView text = (TextView) container.findViewById(R.id.title);
-
- if (icon != null) {
- img.setImageDrawable(icon);
- }
-
- if (title != null) {
- text.setText(title);
- }
-
- if (listener != null) {
- container.setOnClickListener(listener);
- }
-
- return container;
- }
-
-
- private void showArrow(int whichArrow, int requested {
- final View showArrow = (whichArrow == R.id.arrow_up) ? mArrowUp : mArrowDown;
- final View hideArrow = (whichArrow == R.id.arrow_up) ? mArrowDown : mArrowUp;
-
- final int arrowWidth = mArrowUp.getMeasuredWidth();
-
- showArrow.setVisibility(View.VISIBLE);
-
- ViewGroup.MarginLayoutParams param = (ViewGroup.MarginLayoutParams)showArrow.getLayoutParams();
-
- param.leftMargin = requestedX - arrowWidth / 2;
-
- hideArrow.setVisibility(View.INVISIBLE);
- }
- }
* This source code was highlighted with Source Code Highlighter
.
Пусть вас не пугает код, использовать его очень просто, теперь попробуем использовать весь этот код.
Не буду приводить весь код, тут все предельно просто.
- final ActionItem first = new ActionItem();
-
- first.setTitle("Dashboard");
- first.setIcon(getResources().getDrawable(R.drawable.dashboard));
- first.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Toast.makeText(TestQuickAction.this, "Dashboard" , Toast.LENGTH_SHORT).show();
- }
- });
-
-
- final ActionItem second = new ActionItem();
-
- second.setTitle("Users & Groups");
- second.setIcon(getResources().getDrawable(R.drawable.kontak));
- second.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Toast.makeText(TestQuickAction.this, "Users & Groups", Toast.LENGTH_SHORT).show();
- }
- });
-
- Button btn1 = (Button) this.findViewById(R.id.btn1);
- btn1.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- QuickAction qa = new QuickAction(v);
-
- qa.addActionItem(first);
- qa.addActionItem(second);
-
- qa.show();
- }
- });
* This source code was highlighted with Source Code Highlighter
.
P.S. используйте в своих приложениях.
P.S.S Оригинал статьи лежит в моем блоге