1. 程式人生 > >【選擇圖片Jar】全屏DialogFragment實現圖片詳情預覽(十)

【選擇圖片Jar】全屏DialogFragment實現圖片詳情預覽(十)

1.前言

上一篇文章我們在最後丟擲了一個問題。到底我們要如何實現圖片的詳情頁的預覽。 如圖:
這裡寫圖片描述

相信大家看了標題已經知道了,我們是用DialogFragment實現我們這個功能的!

嘿嘿,可能這個時候會有點驚訝,原來DialogFragment還有這樣的效果?

奧祕在哪裡呢?等下我們就會來揭曉。

再說兩句~~Dialog和Fragment一直是我們開發中又愛又恨的兩個東西,Dialog的Api繁多複雜,難以使用! Fragment生命週期很難精準把握,而奇淫巧技非常多!

關於Dialog的問題,Google特意推出了DialogFragment來解決Dialog本身這個原生控制元件的弱點和不足,目前Google官方推薦使用DialogFragment,而且在實際開發中,發現的確是DialogFragment好用!

那關於Fragment的這個問題,我目前也在爬坑收集各種BUG和技巧中,之後學有所成,再回來分享吧!!因為這個不是三兩句話可以完整概括的。 下面附上一條連線:,有興趣的可以學習完本課程之後看看
關於 Android,用多個 activity,還是單 activity 配合 fragment?-稀土掘金

2.FullScreenFragment佈局實現

還是那個問題,我們不能打包資原始檔進入Jar所以,還是要手動寫程式碼,雖然過程比較繁瑣複雜,但是還是要克服一下,這一次的痛苦,是為日後的快速打下基礎!

public class FullScreenFragmentLayout extends
RelativeLayout {
/** * Bar條 */ private RelativeLayout mBar; /** * 返回按鈕的圖片的id,刪除的圖片id,Bar條底色 */ private int mBackIconId, mDeleteIconId, mBarColorId; /** * Bar條中左邊的返回ImageView,右邊的返回ImageView */ private ImageView mBackIv, mDeleteIv; /** * Bar條中的文字控制元件 */
private TextView mNumTv; /** * ViewPager空間 */ private ViewPager mViewPager; /** * Bar條高度 */ private int mBarHeight; /** * 圖示的寬度 */ private int mIconWidth; /** * 圖示距離邊界的大小 */ private int mIconMarginSide; /** * 文字控制元件距離邊界的大小 */ private int mTextMarginSide; /** * 文字大小 */ private int mTextSize; /** * 文字顏色 */ private int mTextColorId; private FullScreenFragmentLayout(Context context, int mBackIconId, int mDeleteIconId, int mBarColorId, int mBarHeight, int mIconWidth, int mIconMarginSide, int mTextMarginSide, int mTextSize, int mTextColorId) { super(context); this.mBackIconId = mBackIconId; this.mDeleteIconId = mDeleteIconId; this.mBarColorId = mBarColorId; this.mBarHeight = mBarHeight; this.mIconWidth = mIconWidth; this.mIconMarginSide = mIconMarginSide; this.mTextMarginSide = mTextMarginSide; this.mTextSize = mTextSize; this.mTextColorId = mTextColorId; initViewPager(); initBar(); } private void initBar() { mBar = new RelativeLayout(getContext()); if (mBarColorId != -1) { mBar.setBackgroundColor(getContext().getResources().getColor( mBarColorId)); } ViewGroup.LayoutParams p = new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, mBarHeight); mBar.setLayoutParams(p); // bar.setBackgroundColor(getContext().getResources() // .getColor(mBarColorId)); mBackIv = new ImageView(getContext()); if (mBackIconId != -1) { mBackIv.setBackgroundResource(mBackIconId); } RelativeLayout.LayoutParams backParams = new RelativeLayout.LayoutParams( mIconWidth, mIconWidth); backParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT); backParams.addRule(RelativeLayout.CENTER_VERTICAL); backParams.leftMargin = mIconMarginSide; mBackIv.setLayoutParams(backParams); mBar.addView(mBackIv); mNumTv = new TextView(getContext()); // 注意 這裡直接 無效 // mNumTv.setTextColor("0xffffff"); if (mTextColorId == -1) { mNumTv.setTextColor(Color.parseColor("#ffffff")); } else { mNumTv.setTextColor(getContext().getResources().getColor( mTextColorId)); } mNumTv.setTextSize(mTextSize); RelativeLayout.LayoutParams numParams = new RelativeLayout.LayoutParams( RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT); numParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT); numParams.addRule(RelativeLayout.CENTER_VERTICAL); int tvMargin = mTextMarginSide; numParams.leftMargin = tvMargin; mNumTv.setLayoutParams(numParams); mBar.addView(mNumTv); mDeleteIv = new ImageView(getContext()); if (mDeleteIconId != -1) { mDeleteIv.setBackgroundResource(mDeleteIconId); } RelativeLayout.LayoutParams deleteParams = new RelativeLayout.LayoutParams( mIconWidth, mIconWidth); deleteParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); deleteParams.addRule(RelativeLayout.CENTER_VERTICAL); deleteParams.rightMargin = mIconMarginSide; mDeleteIv.setLayoutParams(deleteParams); mBar.addView(mDeleteIv); this.addView(mBar); } private void initViewPager() { mViewPager = new ViewPager(getContext()); ViewGroup.LayoutParams p = new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); mViewPager.setLayoutParams(p); this.addView(mViewPager); } public ViewPager getViewPager() { return mViewPager; } public TextView getNumberTextView() { return mNumTv; } public RelativeLayout getBar() { return mBar; } public static class Builder { private Context mContext; /** * 返回按鈕的圖片的id,刪除的圖片id,Bar條底色 */ private int mBackIconId, mDeleteIconId, mBarColorId; /** * Bar條高度 */ private int mBarHeight; /** * 圖示的寬度 */ private int mIconWidth; /** * 圖示距離邊界的大小 */ private int mIconMarginSide; /** * 文字控制元件距離邊界的大小 */ private int mTextMarginSide; /** * 文字大小 */ private int mTextSize; /** * 文字顏色 */ private int mTextColorId; public Builder(Context context) { mContext = context; // 初始化預設的大小 initDefaultConfig(); } private void initDefaultConfig() { // 獲取螢幕高度 int screenHeight = ScreenUtil.getScreenHeight(mContext); // 獲取螢幕寬度 int screenWidth = ScreenUtil.getScreenWidth(mContext); // bar高度為1/13 mBarHeight = screenHeight / 13; mIconWidth = screenWidth / 13; mIconMarginSide = mIconWidth / 7; mTextSize = (int) (mIconMarginSide * 1.5); mTextMarginSide = mTextSize; mBackIconId = mBarColorId = mDeleteIconId = mTextColorId = -1; } public FullScreenFragmentLayout build() { return new FullScreenFragmentLayout(mContext, mBackIconId, mDeleteIconId, mBarColorId, mBarHeight, mIconWidth, mIconMarginSide, mTextMarginSide, mTextSize, mTextColorId); } public Builder setBarHeight(int height) { mBarHeight = height; return this; } public Builder setBarColorId(int colorId) { mBarColorId = colorId; return this; } public Builder setTextSize(int size) { mTextSize = size; return this; } public Builder setTextMarginLeftSize(int marginSize) { mTextMarginSide = marginSize; return this; } public Builder setTextColorId(int id) { mTextColorId = id; return this; } public Builder setIconSize(int size) { mIconWidth = size; return this; } public Builder setIconMarginSize(int marginSize) { mIconMarginSide = marginSize; return this; } public Builder setBackIconDrawableId(int id) { mBackIconId = id; return this; } public Builder setDeleteIconDrawableId(int id) { mDeleteIconId = id; return this; } } }

這裡我們採用了Builder模式進行建立,原因是因為可設定引數太多,採用這種模式比較方便建立。

注意一下Builder構造方式裡面對部分引數進行了預設大小處理,這是為了能夠正常顯示出來。

private void initDefaultConfig() {
            // 獲取螢幕高度
            int screenHeight = ScreenUtil.getScreenHeight(mContext);
            // 獲取螢幕寬度
            int screenWidth = ScreenUtil.getScreenWidth(mContext);
            // bar高度為1/13
            mBarHeight = screenHeight / 13;

            mIconWidth = screenWidth / 13;

            mIconMarginSide = mIconWidth / 7;

            mTextSize = (int) (mIconMarginSide * 1.5);

            mTextMarginSide = mTextSize;

            mBackIconId = mBarColorId = mDeleteIconId = mTextColorId = -1;
        }

即這段程式碼。 對id設定為-1表示標記該位沒有設定值。

佈局程式碼寫起來很慢,也很繁瑣。 所以要有耐心! 如果還不太熟悉的話,可以查閱相關資料,這裡就不一個一個來講了!

3.FullScreenFragment的實現

OK!這裡也是一個大工程!上好廁所, 拿好板凳圍觀吧。

首先來揭曉DialogFragment的奧祕:

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 設定全屏
        setStyle(DialogFragment.STYLE_NO_TITLE,
                android.R.style.Theme_Black_NoTitleBar);
    }

就是這一行程式碼~ 具體的還有其他樣式就不在這裡講述了。大家可以看看官方文件。
官方文件:DialogFragment -不用翻牆也可以看!
那麼下面我們看看構造方法:

    public static FullScreenFragment newInstance(int barColorId,
            int backIconId, int deleteIconId) {
        FullScreenFragment f = new FullScreenFragment();
        Bundle b = new Bundle();
        b.putInt(KEY_BACK_ICON_ID, backIconId);
        b.putInt(KEY_DELETE_ICON_ID, deleteIconId);
        b.putInt(KEY_BAR_COLOR_ID, barColorId);
        f.setArguments(b);
        return f;
    }

    public static FullScreenFragment newInstance(int barColorId, int barHeight,
            int backIconId, int deleteIconId, int iconWidth,
            int iconMarginSide, int textColor, int textSize,
            int textMarginLeftSize) {
        FullScreenFragment f = new FullScreenFragment();
        Bundle b = new Bundle();
        b.putInt(KEY_BAR_COLOR_ID, barColorId);
        b.putInt(KEY_BAR_HEIGHT, barHeight);
        b.putInt(KEY_BACK_ICON_ID, backIconId);
        b.putInt(KEY_DELETE_ICON_ID, deleteIconId);
        b.putInt(KEY_ICON_SIZE, iconWidth);
        b.putInt(KEY_ICON_MARGIN, iconMarginSide);
        b.putInt(KEY_TEXT_COLOR, textColor);
        b.putInt(KEY_TEXT_SIZE, textSize);
        b.putInt(KEY_TEXT_MARGIN, textMarginLeftSize);
        f.setArguments(b);
        return f;
    }

    private FullScreenFragment() {

    }

這裡提供了兩個構造方法。有的同學可能有疑問了,為什麼要這樣寫呢?

其實我們可以從Google官方的很多程式碼看到這樣的寫法,通過setArguments(..);來傳遞資訊,這是為了防止旋轉之後,Android預設呼叫Fragment無參構造而產生的資訊丟失。 具體的可以瞭解其他相關資料。

回到正題,其實上面那一堆東西都是為了從外部獲取資原始檔,或者樣式,來建立我們FullScreenFragmentLayout的佈局,這可以更加適應不同專案的需要。

下面我們來看看onCreateView方法:

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        // 建立佈局
        mRootView = initLayout();
        // 獲取控制元件
        mViewPager = mRootView.getViewPager();
        mNumberTv = mRootView.getNumberTextView();
        mBack = mRootView.getBackImageView();
        mDelete = mRootView.getDeleteImageView();

        // 初始化ViewPager
        initViewPager();
        // 改變文字標題
        postionChange(mCurrentPostion);
        // 要在設定完Adapter之後呼叫 不然沒效果
        mViewPager.setCurrentItem(mCurrentPostion);
        // 初始化監聽
        initBarListener();
        return mRootView;
    }

相信都很好理解。

下面貼上其他程式碼:

    private void initViewPager() {
        // 如果為空或者為0則返回
        if (mPaths == null || mPaths.size() == 0)
            return;
        mImageViews = new ImageView[mPaths.size()];
        for (int i = 0; i < mPaths.size(); i++) {
            mImageViews[i] = new ImageView(getActivity());
        }
        // mViewPager.setOffscreenPageLimit(0);
        mPagerAdapter = new PagerAdapter() {

            @Override
            public boolean isViewFromObject(View paramView, Object paramObject) {
                return paramView == paramObject;
            }

            @Override
            public int getCount() {
                return mPaths.size();
            }

            @Override
            public void destroyItem(ViewGroup container, int position,
                    Object object) {
                ((ViewPager) container).removeView(mImageViews[position]);
            }

            @Override
            public Object instantiateItem(ViewGroup container, int position) {
                ImageView i = mImageViews[position];
                ImageLoaderWrapper.loadFromFile(i, mPaths.get(position));
                ((ViewPager) container).addView(i, 0);
                return i;
            }
        };

        mViewPager.setAdapter(mPagerAdapter);

        mViewPager.addOnPageChangeListener(new OnPageChangeListener() {

            @Override
            public void onPageSelected(int paramInt) {
                // 當前位置
                mCurrentPosition = paramInt;
                postionChange(mCurrentPosition);

            }

            @Override
            public void onPageScrolled(int paramInt1, float paramFloat,
                    int paramInt2) {
                // 上一個位置 偏移量 下一個位置
            }

            @Override
            public void onPageScrollStateChanged(int paramInt) {
                // 這裡是滑動的狀態
            }
        });
    }

    /**
     * 改變位置
     * 
     * @param position
     */
    protected void postionChange(int position) {
        mNumberTv.setText(position + 1 + "/" + mPaths.size());
    }

        @Override
    public void onClick(View v) {
        String tag = (String) v.getTag();
        switch (tag) {
        case "back":
            this.dismiss();
            break;
        case "delete":
            // 刪除
            break;
        }
    }

相信這些程式碼也難不倒大家。

稍微解釋一下是,如果沒有設定值就返回-1。這樣可以用來方便構造我們的FullScreenFragmentLayout

還有的就是tag的用法,之前的文章也講過,這裡也不再說了~

然後我們要對外暴露兩個方法,以便我們改變ViewPager顯示的位置以及,所展示的圖片列表:

    public void setList(List<String> list) {
        mPaths = list;
    }

    public void setCurrentPosition(int position) {
        mCurrentPostion = position;
    }

OK那再加上一些必要的東西,基本的FullScreenFragment就出來了。

public class FullScreenFragment extends DialogFragment implements
        OnClickListener {
    private static final String KEY_BAR_COLOR_ID = "bar_color";
    private static final String KEY_BAR_HEIGHT = "bar_height";
    private static final String KEY_BACK_ICON_ID = "back_icon";
    private static final String KEY_DELETE_ICON_ID = "delete_icon";
    private static final String KEY_ICON_MARGIN = "icon_margin";
    private static final String KEY_ICON_SIZE = "icon_size";
    private static final String KEY_TEXT_COLOR = "text_color";
    private static final String KEY_TEXT_SIZE = "text_size";
    private static final String KEY_TEXT_MARGIN = "text_margin";
    private FullScreenFragmentLayout mRootView;

    private ImageView mBack, mDelete;
    private ViewPager mViewPager;
    /**
     * 數字的TextView
     */
    private TextView mNumberTv;
    /**
     * ImageView集合
     */
    private ImageView[] mImageViews;
    /**
     * 路徑集合
     */
    private List<String> mPaths;
    /**
     * 當前位置
     */
    private int mCurrentPostion = -1;

    private PagerAdapter mPagerAdapter;

    public static FullScreenFragment newInstance(int barColorId,
            int backIconId, int deleteIconId) {
        FullScreenFragment f = new FullScreenFragment();
        Bundle b = new Bundle();
        b.putInt(KEY_BACK_ICON_ID, backIconId);
        b.putInt(KEY_DELETE_ICON_ID, deleteIconId);
        b.putInt(KEY_BAR_COLOR_ID, barColorId);
        f.setArguments(b);
        return f;
    }

    public static FullScreenFragment newInstance(int barColorId, int barHeight,
            int backIconId, int deleteIconId, int iconWidth,
            int iconMarginSide, int textColor, int textSize,
            int textMarginLeftSize) {
        FullScreenFragment f = new FullScreenFragment();
        Bundle b = new Bundle();
        b.putInt(KEY_BAR_COLOR_ID, barColorId);
        b.putInt(KEY_BAR_HEIGHT, barHeight);
        b.putInt(KEY_BACK_ICON_ID, backIconId);
        b.putInt(KEY_DELETE_ICON_ID, deleteIconId);
        b.putInt(KEY_ICON_SIZE, iconWidth);
        b.putInt(KEY_ICON_MARGIN, iconMarginSide);
        b.putInt(KEY_TEXT_COLOR, textColor);
        b.putInt(KEY_TEXT_SIZE, textSize);
        b.putInt(KEY_TEXT_MARGIN, textMarginLeftSize);
        f.setArguments(b);
        return f;
    }

    private FullScreenFragment() {

    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 設定全屏
        setStyle(DialogFragment.STYLE_NO_TITLE,
                android.R.style.Theme_Black_NoTitleBar);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        // if (mRootView == null) {
        // 建立佈局
        mRootView = initLayout();
        // }
        // mViewPager = (ViewPager) view.findViewById(R.id.vp);
        // 獲取空間
        mViewPager = mRootView.getViewPager();
        mNumberTv = mRootView.getNumberTextView();
        mBack = mRootView.getBackImageView();
        mDelete = mRootView.getDeleteImageView();
        // mPaths = new ArrayList<String>();

        // 初始化ViewPager
        initViewPager();
        // 改變文字標題
        postionChange(mCurrentPostion);
        // 要在設定完Adapter之後呼叫 不然沒效果
        mViewPager.setCurrentItem(mCurrentPostion);
        // 初始化監聽
        initBarListener();
        return mRootView;
    }

    private void initBarListener() {
        mBack.setTag("back");
        mDelete.setTag("delete");
        mBack.setOnClickListener(this);
        mDelete.setOnClickListener(this);
    }

    private FullScreenFragmentLayout initLayout() {
        Bundle b = getArguments();
        int barHeight = b.getInt(KEY_BAR_HEIGHT, -1);
        int barColorId = b.getInt(KEY_BAR_COLOR_ID, -1);
        int backIconId = b.getInt(KEY_BACK_ICON_ID, -1);
        int deleteIconId = b.getInt(KEY_DELETE_ICON_ID, -1);
        int iconSize = b.getInt(KEY_ICON_SIZE, -1);
        int iconMargin = b.getInt(KEY_ICON_MARGIN, -1);
        int textColorId = b.getInt(KEY_TEXT_COLOR, -1);
        int textSize = b.getInt(KEY_TEXT_SIZE, -1);
        int textMargin = b.getInt(KEY_TEXT_MARGIN, -1);
        FullScreenFragmentLayout.Builder builder = new FullScreenFragmentLayout.Builder(
                getActivity());
        if (barHeight != -1) {
            builder.setBarHeight(barHeight);
        }
        if (barColorId != -1) {
            builder.setBarColorId(barColorId);
        }
        if (backIconId != -1) {
            builder.setBackIconDrawableId(backIconId);
        }
        if (deleteIconId != -1) {
            builder.setDeleteIconDrawableId(deleteIconId);
        }
        if (iconSize != -1) {
            builder.setIconSize(iconSize);
        }
        if (iconMargin != -1) {
            builder.setIconMarginSize(iconMargin);
        }
        if (textColorId != -1) {
            builder.setTextColorId(textColorId);
        }
        if (textSize != -1) {
            builder.setTextSize(textSize);
        }
        if (textMargin != -1) {
            builder.setTextMarginLeftSize(textMargin);
        }
        return builder.build();
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
    }

    private void initViewPager() {
        // 如果為空或者為0則返回
        if (mPaths == null || mPaths.size() == 0)
            return;
        System.out.println("initViewPager Context = " + getActivity());
        mImageViews = new ImageView[mPaths.size()];
        for (int i = 0; i < mPaths.size(); i++) {
            mImageViews[i] = new ImageView(getActivity());
        }
        mViewPager.setOffscreenPageLimit(2);
        mPagerAdapter = new PagerAdapter() {
            @Override
            public boolean isViewFromObject(View paramView, Object paramObject) {
                // 判斷當前是否一致,一致則繪製View出來
                return paramView == paramObject;
            }

            @Override
            public int getCount() {
                return mPaths.size();
            }

            @Override
            public void destroyItem(ViewGroup container, int position,
                    Object object) {
                System.out.println("destroyItem: viewPager = "
                        + mViewPager.toString() + " container = " + container
                        + " obj = " + object);
                // ((ViewPager) container).removeView(mImageViews[position]);
                View v = (View) object;
                // String vTag = (String) v.getTag();
                // if (mMovedPath != null && vTag.equals(mMovedPath)) {
                ((ViewPager) container).removeView(v);
                v = null;
                // }
            }

            @Override
            public Object instantiateItem(ViewGroup container, int position) {
                System.out.println("destroyItem: viewPager = "
                        + mViewPager.toString() + " container = " + container);
                ImageView i = mImageViews[position];
                String path = mPaths.get(position);
                i.setTag(path);
                ImageLoaderWrapper.loadFromFile(i, path);
                ((ViewPager) container).addView(i);
                System.out.println("instantiateItem");
                return i;
            }

            @Override
            public int getItemPosition(Object object) {
                System.out.println("getItemPosition: object =" + object);
                return POSITION_NONE;
            }

            @Override
            public void notifyDataSetChanged() {
                System.out.println("notifyDataSetChanged");
                super.notifyDataSetChanged();
            }

            @Override
            public void startUpdate(ViewGroup container) {

            }

            @Override
            public void finishUpdate(ViewGroup container) {

            }
        };

        mViewPager.setAdapter(mPagerAdapter);

        mViewPager.addOnPageChangeListener(new OnPageChangeListener() {

            @Override
            public void onPageSelected(int paramInt) {
                // 當前位置
                mCurrentPostion = paramInt;
                postionChange(mCurrentPostion);
            }

            @Override
            public void onPageScrolled(int paramInt1, float paramFloat,
                    int paramInt2) {
                // 上一個位置 偏移量 下一個位置
            }

            @Override
            public void onPageScrollStateChanged(int paramInt) {
                // 這裡是滑動的狀態
            }
        });
    }

    /**
     * 改變位置
     * 
     * @param position
     */
    protected void postionChange(int position) {
        mNumberTv.setText(position + 1 + "/" + mPaths.size());
    }

    public void setList(List<String> list) {
        mPaths = list;
    }

    public void setCurrentPosition(int position) {
        mCurrentPostion = position;
    }

    @Override
    public void onClick(View v) {
        String tag = (String) v.getTag();
        switch (tag) {
        case "back":
            this.dismiss();
            break;
        case "delete":

            break;
        }
    }
}

OK我們繼續完善一下邏輯,我們還有刪除這個邏輯沒有實現,具體的邏輯如下:

    @Override
    public void onClick(View v) {
        ....
        case "delete":
            mPaths.remove(mCurrentPostion);
            mPagerAdapter.notifyDataSetChanged();
            mCurrentPostion = mViewPager.getCurrentItem();
            postionChange(mCurrentPostion);
            break;
        }
        ...
    }

至此是不是以為已經完成了? 沒有哦! 因為我們還要通知外面的那個展示列表更新哦!
所以我們需要在這個DialogFragment dismiss的時候判斷一下是否需要對外部進行更新!

我們依舊採用介面回撥的思想:

    @Override
    public void onClick(View v) {
        ....
        case "delete":
            if (!mNeedToUpdate) {
                mNeedToUpdate = true;
            }
            mPaths.remove(mCurrentPostion);
            if (mPaths.size() == 0) {
                dismiss();
                return;
            }
            mPagerAdapter.notifyDataSetChanged();
            mCurrentPostion = mViewPager.getCurrentItem();
            postionChange(mCurrentPostion);
            break;
        }
        ...
    }

    @Override
    public void dismiss() {
        super.dismiss();
        if (mNeedToUpdate) {
            mCallback.update(mPaths);
        }
    }

    public void setUpdateCallback(UpdateCallback callback) {
        mCallback = callback;
    }

    public interface UpdateCallback {
        void update(List<String> mPaths);
    }

在DialogFragment消失的時候,通知他去更新!

最後我們還要監聽一下使用者的back實體鍵:

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        this.getDialog().setOnKeyListener(new OnKeyListener() {
            public boolean onKey(DialogInterface dialog, int keyCode,
                    KeyEvent event) {
                if (keyCode == KeyEvent.KEYCODE_BACK) {
                    dismiss();
                    return true;
                } else {
                    return false;
                }
            }
        });
    }

當用戶按下back鍵的時候,我們也讓它dissmiss()

OK!至此FullScreenFragment就這樣完成啦!!

那麼我們現在看看Controller的程式碼!

4.完整的ChosenPhotoViewController

那麼Controller中的click程式碼就可以變成:

    ....
    @Override
    public void click(int position) {
        if (position == mPaths.size()) {
            // 跳轉邏輯
            ....
        } else {
            if (mFullFragment == null) {
                throw new IllegalArgumentException(
                        "FullScreenFragment is null. you should invoke setDetailsFragment first");
            }
            if (mManager == null) {
                throw new IllegalArgumentException(
                        "FragmentManager is null. you should invoke setDetailsFragment first");
            }
            mFullFragment.setList(mPaths);
            mFullFragment.setCurrentPosition(position);
            mFullFragment.show(mManager, "FullFragment");
        }
    }
    ....

這裡需要注意一下 DialogFragment的show是非同步的!非同步的!非同步的!

所以,在DialogFragment中,我們對外暴露的方法裡面,一定不能涉及上下文的操作,也不能涉及View相關的程式碼!

這個坑我在開發的時候花了好長的時候,一開始我是在

mFullFragment.setList(mPaths);

才開始建立PagerAdapter,然後當我呼叫

mViewPager.setAdapter(mAdapter)

死活報的都是空指標異常

所以要好好注意這裡!

到這裡還沒有完哦,我們還要在Controller中加一個對外暴露的方法,傳如FullScreenFragment例項,以及FragmentManager

public void setDetailsFragment(@NonNull FragmentManager manager,
    @NonNull FullScreenFragment fragment) {
        mFullFragment = fragment;
        mManager = manager;
        //設定回撥監聽!
        mFullFragment.setUpdateCallback(new UpdateCallback() {

            @Override
            public void update(List<String> paths) {
                mAdapter.update(paths);
            }
        });
}

OK!那現在完整的ChosenPhotoController的完整程式碼也呼之欲出啦!

public class ChosenPhotoViewController extends BaseController {
    /**
     * 一行圖片的數量
     */
    private int mNumColumuns;
    /**
     * +號圖片的資源Id
     */
    private int mAddIconId;
    /**
     * 圖片路徑
     */
    private List<String> mPaths;
    /**
     * +號圖片,介面回撥
     */
    private AddIconAction mAction;
    private IPhotoGridView mView;
    private ChosenPhotoAdapter mAdapter;

    private FragmentManager mManager;
    private FullScreenFragment mFullFragment;

    public ChosenPhotoViewController(int numColumns, int addIconId) {
        mAddIconId = addIconId;
        mNumColumuns = numColumns;
        mPaths = new ArrayList<String>();
    }

    /**
     * 設定監聽,主要是Controller和View聯動使用 不需要手動呼叫
     * 
     * @param listener
     */
    @Override
    public void setPhotoViewListener(IPhotoGridView view) {
        mView = view;
        mAdapter = new ChosenPhotoAdapter(mView.getGridView().getContext(),
                mPaths, mNumColumuns, mAddIconId);
        mView.bindAdapter(mAdapter);
    }

    @Override
    public List<String> getPaths() {
        return mPaths;
    }

    @Override
    public void setAdapter(List<String> paths) {
        if (mView == null)
            throw new IllegalArgumentException(
                    "mListener is null. you should invoke ChosenPhotoGridView's bindController() first");
        mPaths = paths;
        mAdapter.update(mPaths);
    }

    @Override
    public void click(int position) {
        if (position == mPaths.size()) {
            if (mAction == null) {
                throw new IllegalArgumentException(
                        "AddIconAction is null. you should invoke setAddIconAction first");
            }
            mAction.onAddClick();
        } else {
            if (mFullFragment == null) {
                throw new IllegalArgumentException(
                        "FullScreenFragment is null. you should invoke setDetailsFragment first");
            }
            if (mManager == null) {
                throw new IllegalArgumentException(
                        "FragmentManager is null. you should invoke setDetailsFragment first");
            }
            mFullFragment.setList(mPaths);
            mFullFragment.setCurrentPosition(position);
            mFullFragment.show(mManager, "FullFragment");
        }
    }

    public void setDetailsFragment(@NonNull FragmentManager manager,
            @NonNull FullScreenFragment fragment) {
        mFullFragment = fragment;
        mManager = manager;
        mFullFragment.setUpdateCallback(new UpdateCallback() {

            @Override
            public void update(List<String> paths) {
                mAdapter.update(paths);
            }
        });
    }

    public void setAddIconAction(AddIconAction action) {
        mAction = action;
    }

    public interface AddIconAction {
        void onAddClick();
    }
}

到時候我們使用起來就是這樣:

mGv = (GalleryGridView) findViewById(R.id.gv);

mController = new ChosenPhotoViewController(4, R.drawable.add);

FullScreenFragment f =FullScreenFragment.newInstance
(R.color.bar,R.drawable.btn_return, R.drawable.btn_delete);
        mController.setDetailsFragment(getSupportFragmentManager(), f);

mController.setAddIconAction(new AddIconAction() {
    @Override
    public void onAddClick() {
        Intent i = new Intent(ShowActivity.this, MainActivity.class);
        startActivityForResult(i, 1);
    }
});

mGv.bindController(mController);

嗯,程式碼還算優雅,也還算比較少!

5.結束語

OK! 現在這個Jar要已經達到了我們日常專案開發所需要的樣子了!!!