【選擇圖片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要已經達到了我們日常專案開發所需要的樣子了!!!