AndroidはすべてのActivityにグローバルカスタムメニューを追加

14103 ワード

最近UIは大いに突発して、2.0に全局のメニューボタンを作ると言って、バラバラを要します......
このボタンの大まかなニーズは、画面右上にButtonを追加し、クリックした後、画面上部と右側に一連の機能ボタンを召喚することです.
私はこのコードを抽出して勝手にdemoを書いて、上図を実現する必要があります.
(ボタン2をクリックした時点で既にログイン画面にある場合はユーザに再度ジャンプする必要がないことを提示し、以下に説明する)
手に入れる必要があります.前にtitleがカスタムViewを使っていたので、右にボタンをつければいいのではないかと思っています.結果はやはり無邪気すぎて、まずこのような効果を実現するには、このレイアウトは書きにくいに違いない.次に、このニマのページにはtitleがないだろう.そして、前にグローバルな懸濁ボタンを作ったことを連想する.しかし、この品物には懸濁窓の権限が必要で、ユーザーが開いていなければ表示できない~~~
そして第一の考えはいろいろな度です.その結果、ネット上にはこのような需要がないことに気づきました.私が探している姿勢が間違っているのではないでしょうか.これはちょっと気まずいですが、自分で車輪を作るしかありません...
ええ、くだらないことをたくさん言って、本題に入りましょう.
すべてのActivityに統合されたグローバルmenuを追加するには、BaseActivityで操作することが考えられます.統合されたビューを追加する以上、BaseActivityのsetContentView()メソッドにmenuビューを追加します.私のやり方は以下の通りです.
    @Override
    public void setContentView(int layoutResID) {
        super.setContentView(layoutResID);
        ((ViewGroup) getWindow().getDecorView()).addView(menu);
    }

このgetDecorView:この方法はトップレベルのビューを取得することです
注意点1:addViewが追加されたビューは、group内の既存のビューとは関係なく左上隅にデフォルトである必要があります.
注意点2:getDecorViewトップビューである以上、タイトルバーを含む画面全体が含まれています.
注意点3:実際のテストにより、タイトルバーの左上隅の座標が座標原点位置であることが判明しました
ここで引用したhttp://blog.csdn.net/rnZuoZuo/article/details/44959873の紹介で、この方法に興味のある子供靴なら自分で資料を探すことができますが、ここでは詳しく紹介しません~~
ここでmenuはカスタムViewで、RelativeLayoutを継承し、画面右上隅にすべてのボタンを追加する簡単なRelativeLayoutをロードします.



    


当然你可以做成动态添加选项按钮,增加拓展性,因为我比较懒,这里就不做这一步了,就只分享我项目用到的,实际上在打算写博客的时候我考虑到这个需求完全可以做成
动态配置的,包括menu的形式与item的个数配置等等都能做成动态的,我后面会提到。


眼尖的童鞋肯定会发现我上面的menu有一个展开与收缩的动画效果,感觉这个menu关键的就是实现这个动画就行了,贴出show()与dismiss()动画实现代码:
show()

     int n = btns.size();
        for (int i = 0; i < n; i++) {
            float curTranslationX = btns.get(i).getTranslationX();
            float curTranslationY = btns.get(i).getTranslationY();
            PropertyValuesHolder valuesHolderX, valuesHolderY;
            if (i <= 1) {//   item
                valuesHolderX = PropertyValuesHolder.ofFloat("translationX", curTranslationX, 
                        ((i - n + 5) * w / 5));//X          
                valuesHolderY = PropertyValuesHolder.ofFloat("translationY", curTranslationY, 0);

            } else {//   item
                valuesHolderX = PropertyValuesHolder.ofFloat("translationX", curTranslationX, 0);
                valuesHolderY = PropertyValuesHolder.ofFloat("translationY", curTranslationY, 
                        (-(i - n) * h / 7));//Y          
            }
            animatorX = ObjectAnimator.ofPropertyValuesHolder(btns.get(i), valuesHolderX, valuesHolderY);
            animatorX.setDuration(250);
            animatorX.setStartDelay(i * 50);
            animatorX.setInterpolator(new AnticipateOvershootInterpolator());
            animatorX.start();
        }

dismiss()
int n = btns.size();
        for (int i = 0; i < n; i++) {
            //         
        float curTranslationX = btns.get(i).getTranslationX();
        float curTranslationY = btns.get(i).getTranslationY();

        PropertyValuesHolder valuesHolderX = PropertyValuesHolder.ofFloat("translationX",
        curTranslationX, initX);
        PropertyValuesHolder valuesHolderY = PropertyValuesHolder.ofFloat("translationY",
        curTranslationY, initY);
        animatorX = ObjectAnimator.ofPropertyValuesHolder(btns.get(i), valuesHolderX, valuesHolderY);
        animatorX.setDuration(250);
        animatorX.setStartDelay(i * 50);
        animatorX.setInterpolator(new AnticipateOvershootInterpolator());
        animatorX.start();
        }

btnsはすべてのサブitemの集合で、animatorはアニメーションクラスで、属性アニメーションに慣れていない子供靴に対してここのコードを見ると少し愚かかもしれませんが、関連資料をたくさん見ることをお勧めします.私はここであまり紹介しません.valuesHolderはmenu主buttonに対する位置で、w,hはそれぞれスクリーンの幅です.
menuの展示形式はこの2つの方法で定義されています.他の展示アニメーションが必要なら、自分の論理に従って修正することができます.円心を囲むメニューを回転したり、90度の衛星メニューを作ったりすることができます.必要に応じて...
最後にこのmenuの住buttonのクリックイベントを見てみましょう.
   btn_start.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {

                if (!isShowing) {
                    if (mChangeListener != null) {
                        mChangeListener.show();//        
                    }
                    show();


                    rl_parent.setFocusable(true);
                    rl_parent.setClickable(true);

                    rl_parent.setBackgroundColor(getResources().getColor(R.color.menuShow));
                    isShowing = !isShowing;


                } else {
                    if (mChangeListener != null) {
                        mChangeListener.dismiss();//        
                    }
                    dismiss();
                    rl_parent.setFocusable(false);
                    rl_parent.setClickable(false);

                    rl_parent.setBackgroundColor(getResources().getColor(R.color.menuDismiss));
                    isShowing = !isShowing;

                }


            }
        });

isShowingはグローバルに表示されているかどうかの状態ですrl_parentはmenuレイアウト全体のフォローレイアウトであり、menuが展開されるとmenuの次のレイヤのコントロールが焦点を失う必要があります.DialogがsetCancelable(false)を設定した効果に似ているので、rl_を設定する必要があります.parentは展開時にフォーカスを取得し,非表示時にフォーカスをキャンセルする.実際にmenuの展開と非表示は視覚的な効果にすぎず、activityのsetcontentviewにaddviewという方法で追加されたmenuはactivityの最上位層とずっと存在しており、ここではshow()とdismiss()のときにrl_parentは透明度の異なる背景色を設定しているだけです
ここのmChangeListenerはmenu内部のインタフェースで、もしあなたのページがmenuの展示と隠しを傍受する必要があるならば、このインタフェースを実現することができて、普通のインタフェースのコールバックで、ここでは何も言うことはありません.menuの各サブitemのクリックイベントもこのような方法で実現したことがあります.以下に2つのインタフェースを貼り付けます.
   public interface MenuChangeListener {
        public void show();

        public void dismiss();
    }

    public interface MenuItemClickListener {
        void menuOneItemClick();

        void menuTwoItemClick();

        void menuThreeItemClick();

        void menuFourItemClick();

        void menuFiveItemClick();

        void menuSixItemClick();

        void menuSevenItemClick();

    }

実際には、各itemのクリックイベントにコールバックを書く必要はありません.あるitemのイベントが固定されている場合は、外部に露出することなくmenuクラスで直接この方法を実現することができます.
私のプロジェクトではitemのすべてのイベントがbaseActivityで実現されていますが、特定のitemが特定のactivityで異なるイベントに応答する必要があるとしたら、
私のやり方はBaseActivityで一時的なActivity変数current_を定義することです.act、各サブActivityで現在のactivityオブジェクトをcurrent_に割り当てますact,
demoのBaseActivityコードは次のとおりです.
package com.aking.globalmenumaster.activity;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.ViewGroup;
import android.widget.Toast;

import com.aking.globalmenumaster.GlobalMenu;

/**
 * Created by aking on 2017/4/6.
 */
public class BaseActivity extends AppCompatActivity {
    private GlobalMenu menu;
    public Activity current_act;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        menu = new GlobalMenu(this);
        menu.setMenuItemClickListener(new GlobalMenu.MenuItemClickListener() {
            @Override
            public void menuOneItemClick() {
                startActivity(new Intent(BaseActivity.this, FullscreenActivity.class));
            }

            @Override
            public void menuTwoItemClick() {
                if (current_act.getClass() == LoginActivity.class) {
                    Toast.makeText(BaseActivity.this, "         ", Toast.LENGTH_LONG).show();
                } else {
                    startActivity(new Intent(BaseActivity.this, LoginActivity.class));
                }

            }

            @Override
            public void menuThreeItemClick() {
                startActivity(new Intent(BaseActivity.this, Main2Activity.class));
            }

            @Override
            public void menuFourItemClick() {
                startActivity(new Intent(BaseActivity.this, Main22Activity.class));
            }

            @Override
            public void menuFiveItemClick() {
                startActivity(new Intent(BaseActivity.this, Main23Activity.class));
            }

            @Override
            public void menuSixItemClick() {
                startActivity(new Intent(BaseActivity.this, ScrollingActivity.class));
            }

            @Override
            public void menuSevenItemClick() {
                startActivity(new Intent(BaseActivity.this, MainActivity.class));
            }
        });


    }

    @Override
    public void setContentView(int layoutResID) {
        super.setContentView(layoutResID);
        ((ViewGroup) getWindow().getDecorView()).addView(menu);
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (menu.isShowing()) {
            menu.dismiss();
        }
    }
}

menuTwoItemClick()のイベントでスタックトップのactivityがログインページかどうかを判断し、そうであればジャンプせずにユーザに提示する.あるactivityでmenuのitemをクリックするにはいくつかのパラメータを別のページに持っていく必要があるとしたら、私の考えは同じようにBaseActivityでこれらのパラメータを格納するための一時的な変数を定義したり、SharedPreferencesを使用したりする必要があります.私のプロジェクトにはこのようなニーズはありませんので、ここには書いていませんが、このようなニーズがある可能性が高いと思います.
説明が必要なのはnew GlobalMenu(this);ここでmenuを初期化するときに渡されるコンテキストオブジェクトは必ずActivityオブジェクトです.menuクラスではこのコンテキストオブジェクトで画面幅を取得する必要があります.もちろん、ここには最適化可能な空間があります.
ここで既知の問題は、menuのメインButtonがスリットのあるベクトルマップである場合、収縮時に下に覆われたitemの一部が表示され、インタフェースに影響を与える場合、ここでは3つの解決策を提供することである.
1>dismiss()に縮小アニメーションのリスナーを登録し、縮小アニメーションが完了した後、閉じたitemを非表示にし、show()にitemを表示します.コードは次のように実現されます.
animatorX.addListener(new Animator.AnimatorListener() {
                @Override
                public void onAnimationStart(Animator animation) {

                }

                @Override
                public void onAnimationEnd(Animator animation) {
                    *//*          ,               
                    *         bug,                      ,menu  show   ,   item              
                    *
                    * *//*
                    if (btns.get(finalI).getVisibility() == VISIBLE) {
                        btns.get(finalI).setVisibility(INVISIBLE);
                    }
                }

                @Override
                public void onAnimationCancel(Animator animation) {

                }

                @Override
                public void onAnimationRepeat(Animator animation) {

                }
            });

このような限界については、私のソースコードでは、この部分のコードは注釈されています.
2>dismiss()に動画リスニングを登録する必要はなく、show()の時に表示し、dismiss()の時に隠すだけで、このような結果は収縮したアニメーションが見えない.
3>第3の案は私個人が最も完璧だと思っています.それはUIに完璧な図を大きく切って、後ろのitemを完全に覆うことができます.そうすれば、彼らの表示と隠蔽をコントロールする必要はありません.ハハハ...
时间は限られていて、こんなに多く绍介して、この中の内容も多くないと感じて、この文章を见た子供靴も简単に自分のグローバルmenuをカスタマイズすることができると信じて、最后にコードを添付して接続をダウンロードします:
http://download.csdn.net/detail/u011907407/9807354
ここは1つのポイントがダウンロードすることができます--私も最近木有ポイントが资源をダウンロードして、通りかかった親切な人は2つのポイントを赏します!!!もしスレ主のようなポイント貧乏人もいれば、資源が必要ならメールボックスを残しておくことができます.返事を見たら、最初に添付ファイルを送ります.