PhotoPickerNewDemo【PhotoPicker0.9.12的个性化修改以及使用(内部glide版本号是4.1.1)】
版权声明:本文为HaiyuKing原创文章,转载请注明出处!
前言
本Demo使用的是PhotoPicker 0.9.12版本,里面集成的glide版本号是4.1.1。这里就不进行特殊的个性化处理了(比如新增NewImagePagerDialogFragment.java用于对话框样式预览图片、新增NewPhotoPickerFragment.java用于单独作为自定义DialogFragment的其中一个Fragment和其他Fragment共存),而是记录下使用步骤(当然了,github上讲解的很清楚了,大家可以直接参考《donglua/PhotoPicker》)。
不过,本文对PhotoPicker进行了简单的修改,对UI进行了部分修改。【所以本Demo最后使用的是方式2——通过引入PhotoPicker这个module的方式】
效果图
代码分析
引入PhotoPicker有两种方式【二选一】
1、通过Gradle方式,在APP的build.gradle中引用【见导入步骤】
2、下载整个压缩包,然后导入PhotoPicker的module,然后修改图片资源
2.1、下载压缩包
2.2、导入PhotoPicker的Module
提示下面的错误:
2.3、解决Plugin with id 'com.novoda.bintray-release' not found.问题
在项目的build.gradle文件中添加以下代码
- // Top-level build file where you can add configuration options common to all sub-projects/modules.
- buildscript {
- repositories {
- google()
- jcenter()
- }
- dependencies {
- classpath 'com.android.tools.build:gradle:3.0.1'
- //解决PhotoPicker的Plugin with id 'com.novoda.bintray-release' not found.
- classpath 'com.novoda:bintray-release:0.5.0'
- // NOTE: Do not place your application dependencies here; they belong
- // in the individual module build.gradle files
- }
- }
- allprojects {
- repositories {
- google()
- jcenter()
- }
- }
- task clean(type: Delete) {
- delete rootProject.buildDir
- }
2.4、修改图片资源(比如__picker_ic_photo_black_48dp.png、__picker_checkbox_marked.png、__picker_checkbox_n.png)
注意:需要修改所有drawable-xxxx目录下的图片
原始的图片资源:
修改后的图片资源:
2.5、添加图片资源【__picker_transparent_bg.png、down_arrow.png、up_arrow.png】
添加到drawable-xxhdpi目录下
2.6、修改drawable目录下的__picker_photo_bg.xml和__picker_checkbox_bg.xml【主要用于替换图片列表项的底部背景图】
原代码1:
- <?xml version="1.0" encoding="utf-8"?>
- <selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_selected="true">
- <shape>
- <stroke android:color="@color/__picker_item_photo_border_selected"
- android:width="1dip"/>
- </shape>
- </item>
- <item>
- <shape>
- <stroke android:color="@color/__picker_item_photo_border_n"
- android:width="1dip"/>
- </shape>
- </item>
- </selector>
__picker_photo_bg.xml
修改后的代码:
- <?xml version="1.0" encoding="utf-8"?>
- <selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_selected="true">
- <shape android:shape="rectangle">
- <stroke android:width="2dip"
- android:color="@color/__picker_item_photo_border_selected"/>
- <solid android:color="@color/__picker_selected_bg"/>
- <solid></solid>
- </shape>
- </item>
- <item android:drawable="@drawable/__picker_transparent_bg">
- <shape android:shape="rectangle">
- <stroke android:width="2dip"
- android:color="@color/__picker_item_photo_border_n"/>
- <!--<solid android:color="#00000000"/>-->
- </shape>
- </item>
- </selector>
原代码2:
- <?xml version="1.0" encoding="utf-8"?>
- <selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_selected="true">
- <layer-list>
- <item>
- <shape>
- <corners android:radius="2dip"/>
- <padding android:top="-2dip"
- android:left="-2dip"
- android:bottom="-2dip"
- android:right="-2dip"/>
- <stroke android:width="1dip"
- android:color="@android:color/white"/>
- </shape>
- </item>
- <item android:drawable="@drawable/__picker_checkbox_marked"/>
- </layer-list>
- </item>
- <item>
- <layer-list>
- <item>
- <shape>
- <corners android:radius="2dip"/>
- <padding android:top="-2dip"
- android:left="-2dip"
- android:bottom="-2dip"
- android:right="-2dip"/>
- <stroke android:width="1dip"
- android:color="@android:color/white"/>
- </shape>
- </item>
- <item android:drawable="@drawable/__picker_checkbox_n"/>
- </layer-list>
- </item>
- </selector>
__picker_checkbox_bg.xml
修改后的
- <?xml version="1.0" encoding="utf-8"?>
- <selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_selected="true">
- <layer-list>
- <!--<item>
- <shape>
- <corners android:radius="10dip"/>
- <padding android:top="-2dip"
- android:left="-2dip"
- android:bottom="-2dip"
- android:right="-2dip"/>
- <stroke android:width="1dip"
- android:color="@android:color/white"/>
- <solid android:color="@android:color/white"></solid>
- </shape>
- </item>-->
- <item android:drawable="@drawable/__picker_checkbox_marked"/>
- </layer-list>
- </item>
- <item>
- <layer-list>
- <!--<item>
- <shape>
- <corners android:radius="10dip"/>
- <padding android:top="-2dip"
- android:left="-2dip"
- android:bottom="-2dip"
- android:right="-2dip"/>
- <stroke android:width="1dip"
- android:color="@android:color/white"/>
- <solid android:color="@android:color/white"></solid>
- </shape>
- </item>-->
- <item android:drawable="@drawable/__picker_checkbox_n"/>
- </layer-list>
- </item>
- </selector>
2.7、修改__picker_fragment_photo_picker.xml文件【主要用于添加图片目录的上下箭头图标】
原代码
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- >
- <android.support.v7.widget.RecyclerView
- android:id="@+id/rv_photos"
- android:layout_width="match_parent"
- android:gravity="center"
- android:layout_weight="1"
- android:layout_height="0dip"
- />
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="?attr/colorPrimary"
- >
- <Button
- android:id="@+id/button"
- android:text="@string/__picker_all_image"
- android:layout_width="wrap_content"
- android:gravity="center"
- android:layout_height="wrap_content"
- style="@style/Widget.AppCompat.ActionButton"
- />
- </LinearLayout>
- </LinearLayout>
__picker_fragment_photo_picker.xml
修改后的代码
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- >
- <android.support.v7.widget.RecyclerView
- android:id="@+id/rv_photos"
- android:layout_width="match_parent"
- android:gravity="center"
- android:layout_weight="1"
- android:layout_height="0dip"
- />
- <View
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:background="#e9e9e9"/>
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="?attr/colorPrimary"
- >
- <!--<Button
- android:id="@+id/button"
- android:text="@string/__picker_all_image"
- android:layout_width="wrap_content"
- android:gravity="center"
- android:layout_height="wrap_content"
- style="@style/Widget.AppCompat.ActionButton"
- />-->
- <TextView
- android:id="@+id/button"
- android:layout_width="0.0dp"
- android:layout_weight="1"
- android:layout_height="match_parent"
- android:text="@string/__picker_all_image"
- android:textColor="@color/__picker_text_120"
- android:textSize="16sp"
- android:drawableRight="@drawable/up_arrow"
- android:drawablePadding="8dp"
- android:paddingLeft="10dp"
- android:paddingRight="10dp"
- android:gravity="center_vertical"
- style="@style/Widget.AppCompat.ActionButton"
- />
- <!-- 现在用不到,只是占位用 -->
- <ImageView
- android:layout_width="0.0dp"
- android:layout_weight="1"
- android:layout_height="match_parent"
- android:src="@drawable/__picker_camera"
- android:layout_gravity="center_vertical"
- android:paddingLeft="15dp"
- android:paddingRight="15dp"
- android:visibility="invisible"/>
- </LinearLayout>
- </LinearLayout>
2.8、修改PhotoPickerFragment.java文件【主要是实现上下箭头的更换功能】
搜索why,查看改动的代码:
- package me.iwf.photopicker.fragment;
- import android.content.ActivityNotFoundException;
- import android.content.Intent;
- import android.content.pm.PackageManager;
- import android.graphics.drawable.Drawable;
- import android.os.Bundle;
- import android.support.annotation.NonNull;
- import android.support.v4.app.Fragment;
- import android.support.v4.app.FragmentActivity;
- import android.support.v4.content.ContextCompat;
- import android.support.v7.widget.DefaultItemAnimator;
- import android.support.v7.widget.ListPopupWindow;
- import android.support.v7.widget.OrientationHelper;
- import android.support.v7.widget.RecyclerView;
- import android.support.v7.widget.StaggeredGridLayoutManager;
- import android.util.Log;
- import android.view.Gravity;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.view.ViewGroup;
- import android.widget.AdapterView;
- import android.widget.PopupWindow;
- import android.widget.TextView;
- import com.bumptech.glide.Glide;
- import com.bumptech.glide.RequestManager;
- import java.io.IOException;
- import java.util.ArrayList;
- import java.util.List;
- import me.iwf.photopicker.PhotoPickerActivity;
- import me.iwf.photopicker.R;
- import me.iwf.photopicker.adapter.PhotoGridAdapter;
- import me.iwf.photopicker.adapter.PopupDirectoryListAdapter;
- import me.iwf.photopicker.entity.Photo;
- import me.iwf.photopicker.entity.PhotoDirectory;
- import me.iwf.photopicker.event.OnPhotoClickListener;
- import me.iwf.photopicker.utils.AndroidLifecycleUtils;
- import me.iwf.photopicker.utils.ImageCaptureManager;
- import me.iwf.photopicker.utils.MediaStoreHelper;
- import me.iwf.photopicker.utils.PermissionsConstant;
- import me.iwf.photopicker.utils.PermissionsUtils;
- import static android.app.Activity.RESULT_OK;
- import static me.iwf.photopicker.PhotoPicker.DEFAULT_COLUMN_NUMBER;
- import static me.iwf.photopicker.PhotoPicker.EXTRA_PREVIEW_ENABLED;
- import static me.iwf.photopicker.PhotoPicker.EXTRA_SHOW_GIF;
- import static me.iwf.photopicker.utils.MediaStoreHelper.INDEX_ALL_PHOTOS;
- /**
- * Created by donglua on 15/5/31.
- */
- public class PhotoPickerFragment extends Fragment {
- private ImageCaptureManager captureManager;
- private PhotoGridAdapter photoGridAdapter;
- private PopupDirectoryListAdapter listAdapter;
- //所有photos的路径
- private List<PhotoDirectory> directories;
- //传入的已选照片
- private ArrayList<String> originalPhotos;
- private int SCROLL_THRESHOLD = 30;
- int column;
- //目录弹出框的一次最多显示的目录数目
- public static int COUNT_MAX = 4;
- private final static String EXTRA_CAMERA = "camera";
- private final static String EXTRA_COLUMN = "column";
- private final static String EXTRA_COUNT = "count";
- private final static String EXTRA_GIF = "gif";
- private final static String EXTRA_ORIGIN = "origin";
- private ListPopupWindow listPopupWindow;
- private RequestManager mGlideRequestManager;
- public static PhotoPickerFragment newInstance(boolean showCamera, boolean showGif,
- boolean previewEnable, int column, int maxCount, ArrayList<String> originalPhotos) {
- Bundle args = new Bundle();
- args.putBoolean(EXTRA_CAMERA, showCamera);
- args.putBoolean(EXTRA_GIF, showGif);
- args.putBoolean(EXTRA_PREVIEW_ENABLED, previewEnable);
- args.putInt(EXTRA_COLUMN, column);
- args.putInt(EXTRA_COUNT, maxCount);
- args.putStringArrayList(EXTRA_ORIGIN, originalPhotos);
- PhotoPickerFragment fragment = new PhotoPickerFragment();
- fragment.setArguments(args);
- return fragment;
- }
- @Override public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setRetainInstance(true);
- mGlideRequestManager = Glide.with(this);
- directories = new ArrayList<>();
- originalPhotos = getArguments().getStringArrayList(EXTRA_ORIGIN);
- column = getArguments().getInt(EXTRA_COLUMN, DEFAULT_COLUMN_NUMBER);
- boolean showCamera = getArguments().getBoolean(EXTRA_CAMERA, true);
- boolean previewEnable = getArguments().getBoolean(EXTRA_PREVIEW_ENABLED, true);
- photoGridAdapter = new PhotoGridAdapter(getActivity(), mGlideRequestManager, directories, originalPhotos, column);
- photoGridAdapter.setShowCamera(showCamera);
- photoGridAdapter.setPreviewEnable(previewEnable);
- listAdapter = new PopupDirectoryListAdapter(mGlideRequestManager, directories);
- Bundle mediaStoreArgs = new Bundle();
- boolean showGif = getArguments().getBoolean(EXTRA_GIF);
- mediaStoreArgs.putBoolean(EXTRA_SHOW_GIF, showGif);
- MediaStoreHelper.getPhotoDirs(getActivity(), mediaStoreArgs,
- new MediaStoreHelper.PhotosResultCallback() {
- @Override public void onResultCallback(List<PhotoDirectory> dirs) {
- directories.clear();
- directories.addAll(dirs);
- photoGridAdapter.notifyDataSetChanged();
- listAdapter.notifyDataSetChanged();
- adjustHeight();
- }
- });
- captureManager = new ImageCaptureManager(getActivity());
- }
- @Override
- public void onResume() {
- super.onResume();
- if(getActivity() instanceof PhotoPickerActivity){
- PhotoPickerActivity photoPickerActivity = (PhotoPickerActivity) getActivity();
- photoPickerActivity.updateTitleDoneItem();
- }
- }
- @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- final View rootView = inflater.inflate(R.layout.__picker_fragment_photo_picker, container, false);
- RecyclerView recyclerView = (RecyclerView) rootView.findViewById(R.id.rv_photos);
- StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(column, OrientationHelper.VERTICAL);
- layoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS);
- recyclerView.setLayoutManager(layoutManager);
- recyclerView.setAdapter(photoGridAdapter);
- recyclerView.setItemAnimator(new DefaultItemAnimator());
- //final Button btSwitchDirectory = (Button) rootView.findViewById(R.id.button);
- final TextView btSwitchDirectory = (TextView) rootView.findViewById(R.id.button);//why
- listPopupWindow = new ListPopupWindow(getActivity());
- listPopupWindow.setWidth(ListPopupWindow.MATCH_PARENT);
- listPopupWindow.setAnchorView(btSwitchDirectory);
- listPopupWindow.setAdapter(listAdapter);
- listPopupWindow.setModal(true);
- listPopupWindow.setDropDownGravity(Gravity.BOTTOM);
- listPopupWindow.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- listPopupWindow.dismiss();
- PhotoDirectory directory = directories.get(position);
- btSwitchDirectory.setText(directory.getName());
- photoGridAdapter.setCurrentDirectoryIndex(position);
- photoGridAdapter.notifyDataSetChanged();
- }
- });
- //添加popwindow隐藏的监听--why
- listPopupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
- @Override
- public void onDismiss() {
- //监听popwindow隐藏的时候的操作
- Drawable drawableUp = ContextCompat.getDrawable(getActivity(),R.drawable.up_arrow);
- drawableUp.setBounds(0, 0, drawableUp.getMinimumWidth(), drawableUp.getMinimumHeight());
- btSwitchDirectory.setCompoundDrawables(null,null,drawableUp,null);
- }
- });
- photoGridAdapter.setOnPhotoClickListener(new OnPhotoClickListener() {
- @Override public void onClick(View v, int position, boolean showCamera) {
- final int index = showCamera ? position - 1 : position;
- List<String> photos = photoGridAdapter.getCurrentPhotoPaths();
- ImagePagerFragment imagePagerFragment =
- ImagePagerFragment.newInstance(photos, index);
- ((PhotoPickerActivity) getActivity()).addImagePagerFragment(imagePagerFragment);
- }
- });
- photoGridAdapter.setOnCameraClickListener(new OnClickListener() {
- @Override public void onClick(View view) {
- if (!PermissionsUtils.checkCameraPermission(PhotoPickerFragment.this)) return;
- if (!PermissionsUtils.checkWriteStoragePermission(PhotoPickerFragment.this)) return;
- openCamera();
- }
- });
- btSwitchDirectory.setOnClickListener(new OnClickListener() {
- @Override public void onClick(View v) {
- if (listPopupWindow.isShowing()) {
- listPopupWindow.dismiss();
- } else if (!getActivity().isFinishing()) {
- adjustHeight();
- //why
- Drawable drawableDown = ContextCompat.getDrawable(getActivity(),R.drawable.down_arrow);
- drawableDown.setBounds(0, 0, drawableDown.getMinimumWidth(), drawableDown.getMinimumHeight());
- btSwitchDirectory.setCompoundDrawables(null,null,drawableDown,null);
- listPopupWindow.show();
- }
- }
- });
- recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
- @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
- super.onScrolled(recyclerView, dx, dy);
- // Log.d(">>> Picker >>>", "dy = " + dy);
- if (Math.abs(dy) > SCROLL_THRESHOLD) {
- mGlideRequestManager.pauseRequests();
- } else {
- resumeRequestsIfNotDestroyed();
- }
- }
- @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
- if (newState == RecyclerView.SCROLL_STATE_IDLE) {
- resumeRequestsIfNotDestroyed();
- }
- }
- });
- return rootView;
- }
- private void openCamera() {
- try {
- Intent intent = captureManager.dispatchTakePictureIntent();
- startActivityForResult(intent, ImageCaptureManager.REQUEST_TAKE_PHOTO);
- } catch (IOException e) {
- e.printStackTrace();
- } catch (ActivityNotFoundException e) {
- Log.e("PhotoPickerFragment", "No Activity Found to handle Intent", e);
- }
- }
- @Override public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == ImageCaptureManager.REQUEST_TAKE_PHOTO && resultCode == RESULT_OK) {
- if (captureManager == null) {
- FragmentActivity activity = getActivity();
- captureManager = new ImageCaptureManager(activity);
- }
- captureManager.galleryAddPic();
- if (directories.size() > 0) {
- String path = captureManager.getCurrentPhotoPath();
- PhotoDirectory directory = directories.get(INDEX_ALL_PHOTOS);
- directory.getPhotos().add(INDEX_ALL_PHOTOS, new Photo(path.hashCode(), path));
- directory.setCoverPath(path);
- photoGridAdapter.notifyDataSetChanged();
- }
- }
- }
- @Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
- if (grantResults.length > 0
- && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
- switch (requestCode) {
- case PermissionsConstant.REQUEST_CAMERA:
- case PermissionsConstant.REQUEST_EXTERNAL_WRITE:
- if (PermissionsUtils.checkWriteStoragePermission(this) &&
- PermissionsUtils.checkCameraPermission(this)) {
- openCamera();
- }
- break;
- }
- }
- }
- public PhotoGridAdapter getPhotoGridAdapter() {
- return photoGridAdapter;
- }
- @Override public void onSaveInstanceState(Bundle outState) {
- captureManager.onSaveInstanceState(outState);
- super.onSaveInstanceState(outState);
- }
- @Override public void onViewStateRestored(Bundle savedInstanceState) {
- captureManager.onRestoreInstanceState(savedInstanceState);
- super.onViewStateRestored(savedInstanceState);
- }
- public ArrayList<String> getSelectedPhotoPaths() {
- return photoGridAdapter.getSelectedPhotoPaths();
- }
- public void adjustHeight() {
- if (listAdapter == null) return;
- int count = listAdapter.getCount();
- count = count < COUNT_MAX ? count : COUNT_MAX;
- if (listPopupWindow != null) {
- listPopupWindow.setHeight(count * getResources().getDimensionPixelOffset(R.dimen.__picker_item_directory_height));
- }
- }
- @Override public void onDestroy() {
- super.onDestroy();
- if (directories == null) {
- return;
- }
- for (PhotoDirectory directory : directories) {
- directory.getPhotoPaths().clear();
- directory.getPhotos().clear();
- directory.setPhotos(null);
- }
- directories.clear();
- directories = null;
- }
- private void resumeRequestsIfNotDestroyed() {
- if (!AndroidLifecycleUtils.canLoadImage(this)) {
- return;
- }
- mGlideRequestManager.resumeRequests();
- }
- }
PhotoPickerFragment.java
2.9、修改__picker_item_photo.xml,设置图片列表项的内边距值
- <?xml version="1.0" encoding="utf-8"?>
- <me.iwf.photopicker.widget.SquareItemLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:padding="3dp"
- >
- <ImageView
- android:padding="1dip"
- android:layout_gravity="center"
- android:id="@+id/iv_photo"
- android:scaleType="centerCrop"
- android:layout_width="match_parent"
- android:background="@drawable/__picker_photo_bg"
- android:layout_height="match_parent"
- android:adjustViewBounds="true"
- />
- <ImageView
- android:layout_alignParentTop="true"
- android:layout_alignParentRight="true"
- android:clickable="true"
- android:paddingTop="10dip"
- android:paddingRight="10dip"
- android:paddingLeft="20dip"
- android:paddingBottom="20dip"
- android:id="@+id/v_selected"
- android:src="@drawable/__picker_checkbox_bg"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- />
- </me.iwf.photopicker.widget.SquareItemLayout>
2.10、修改图片列表项选中后的颜色值(colors.xml文件中修改)
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <color name="__picker_pager_bg">#CA000000</color>
- <color name="__picker_selected_bg">#44000000</color>
- <color name="__picker_black_40">#282828</color>
- <color name="__picker_common_primary">#f3f3f3</color>
- <color name="__picker_text_40">#282828</color>
- <color name="__picker_text_80">#505050</color>
- <color name="__picker_text_120">#787878</color>
- <!--<color name="__picker_item_photo_border_selected">#ff99cc00</color>-->
- <!--why-->
- <color name="__picker_item_photo_border_selected">#1A78EC</color>
- <color name="__picker_item_photo_border_n">#33ffffff</color>
- </resources>
至此,PhotoPicker基本上修改完了,后续可以根据需求继续修改。下面就是运用到APP中的步骤【导入步骤跟方式1几乎一样,不同的就是app的build.gradle导入的photopicker不一样】。
2.11、在APP的build.gradle文件添加以下代码
- apply plugin: 'com.android.application'
- android {
- compileSdkVersion 27
- defaultConfig {
- applicationId "com.why.project.photopickernewdemo"
- minSdkVersion 16
- targetSdkVersion 27
- versionCode 1
- versionName "1.0"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
- }
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- }
- }
- dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar'])
- implementation 'com.android.support:appcompat-v7:27.1.1'
- implementation 'com.android.support.constraint:constraint-layout:1.1.2'
- testImplementation 'junit:junit:4.12'
- androidTestImplementation 'com.android.support.test:runner:1.0.2'
- androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
- //PhotoPicker
- //compile 'me.iwf.photopicker:PhotoPicker:0.9.12@aar'
- //方式2:使用自己导入并且修改后的module
- implementation project(':PhotoPicker')
- //compile 'com.android.support:appcompat-v7:27.1.1'//需要注释,因为新建项目都会自动引用这个appcompat-v7
- compile 'com.android.support:recyclerview-v7:27.1.1'
- compile 'com.android.support:design:27.1.1'
- compile 'com.github.bumptech.glide:glide:4.1.1'
- }
2.12、在APP的AndroidManifest.xml中添加以下代码
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.why.project.photopickernewdemo">
- <application
- android:allowBackup="true"
- android:icon="@mipmap/ic_launcher"
- android:label="@string/app_name"
- android:roundIcon="@mipmap/ic_launcher_round"
- android:supportsRtl="true"
- android:theme="@style/AppTheme">
- <activity android:name=".MainActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
- </activity>
- <!-- PhotoPicker -->
- <activity android:name="me.iwf.photopicker.PhotoPickerActivity"
- android:theme="@style/customTheme"
- />
- <activity android:name="me.iwf.photopicker.PhotoPagerActivity"
- android:theme="@style/customTheme"/>
- </application>
- </manifest>
2.13、在styles.xml文件中添加以下代码
- <resources>
- <!-- Base application theme. -->
- <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
- <!-- Customize your theme here. -->
- <item name="colorPrimary">@color/colorPrimary</item>
- <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
- <item name="colorAccent">@color/colorAccent</item>
- </style>
- <!-- PhotoPicker -->
- <style name="customTheme" parent="Theme.AppCompat.Light.NoActionBar">
- <!-- 解开注释的话,右侧的完成文本始终是设置的颜色,无法实现禁用状态下是灰色的功能 -->
- <!--<item name="actionBarTheme">@style/actionBarTheme</item>-->
- <!--背景颜色值-->
- <item name="colorPrimary">#ffffff</item>
- <!--导航栏高度值-->
- <item name="actionBarSize">52dp</item>
- <!-- 状态栏着色 -->
- <item name="colorPrimaryDark">#378dfc</item>
- </style>
- <style name="actionBarTheme" parent="ThemeOverlay.AppCompat.Dark.ActionBar">
- <!--标题颜色值-->
- <item name="android:textColorPrimary">#434343</item>
- <!--右侧完成文本的大小值-->
- <item name="android:textSize">16sp</item>
- <!--右侧完成文本的颜色值-->
- <item name="android:actionMenuTextColor">#1A78EC</item>
- </style>
- </resources>
具体使用参考《三、使用方法》
使用步骤
一、项目组织结构图
注意事项:
1、 导入类文件后需要change包名以及重新import R文件路径
2、 Values目录下的文件(strings.xml、dimens.xml、colors.xml等),如果项目中存在,则复制里面的内容,不要整个覆盖
二、导入步骤【方式1的导入步骤】
(1)在app的build.gradle文件中导入PhotoPicker【修改recyclerview、design的版本号和appcompat-v7统一】
注意:appcompat-v7
version >= 23.0.0
- apply plugin: 'com.android.application'
- android {
- compileSdkVersion 27
- defaultConfig {
- applicationId "com.why.project.photopickernewdemo"
- minSdkVersion 16
- targetSdkVersion 27
- versionCode 1
- versionName "1.0"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
- }
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- }
- }
- dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar'])
- implementation 'com.android.support:appcompat-v7:27.1.1'
- implementation 'com.android.support.constraint:constraint-layout:1.1.2'
- testImplementation 'junit:junit:4.12'
- androidTestImplementation 'com.android.support.test:runner:1.0.2'
- androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
- //PhotoPicker
- compile 'me.iwf.photopicker:PhotoPicker:0.9.12@aar'
- //compile 'com.android.support:appcompat-v7:27.1.1'//需要注释,因为新建项目都会自动引用这个appcompat-v7
- compile 'com.android.support:recyclerview-v7:27.1.1'
- compile 'com.android.support:design:27.1.1'
- compile 'com.github.bumptech.glide:glide:4.1.1'
- }
(2)在APP的styles.xml文件中自定义样式(颜色、高度值等)
- <resources>
- <!-- Base application theme. -->
- <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
- <!-- Customize your theme here. -->
- <item name="colorPrimary">@color/colorPrimary</item>
- <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
- <item name="colorAccent">@color/colorAccent</item>
- </style>
- <!-- PhotoPicker -->
- <style name="customTheme" parent="Theme.AppCompat.Light.NoActionBar">
- <!-- 解开注释的话,右侧的完成文本始终是设置的颜色,无法实现禁用状态下是灰色的功能 -->
- <!--<item name="actionBarTheme">@style/actionBarTheme</item>-->
- <!--背景颜色值-->
- <item name="colorPrimary">#ffffff</item>
- <!--导航栏高度值-->
- <item name="actionBarSize">52dp</item>
- <!-- 状态栏着色 -->
- <item name="colorPrimaryDark">#378dfc</item>
- </style>
- <style name="actionBarTheme" parent="ThemeOverlay.AppCompat.Dark.ActionBar">
- <!--标题颜色值-->
- <item name="android:textColorPrimary">#434343</item>
- <!--右侧完成文本的大小值-->
- <item name="android:textSize">16sp</item>
- <!--右侧完成文本的颜色值-->
- <item name="android:actionMenuTextColor">#1A78EC</item>
- </style>
- </resources>
(3)在APP的AndroidManifest.xml中添加以下代码【注意:使用上面自定义的样式】
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.why.project.photopickernewdemo">
- <application
- android:allowBackup="true"
- android:icon="@mipmap/ic_launcher"
- android:label="@string/app_name"
- android:roundIcon="@mipmap/ic_launcher_round"
- android:supportsRtl="true"
- android:theme="@style/AppTheme">
- <activity android:name=".MainActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
- </activity>
- <!-- PhotoPicker -->
- <activity android:name="me.iwf.photopicker.PhotoPickerActivity"
- android:theme="@style/customTheme"
- />
- <activity android:name="me.iwf.photopicker.PhotoPagerActivity"
- android:theme="@style/customTheme"/>
- </application>
- </manifest>
三、使用方法
(1)在项目中实现Recyclerview基本数据展现【比较简单,省略】【或者参考《Android快速开发常用知识点系列目录》下的RecyclerView篇章相关文章】
注意:PictureAdapter.java中使用的Glide是4.1.1版本,所以写法跟之前的Glide3.7.0版本是不一样的。
- package com.why.project.photopickernewdemo.adapter;
- import android.content.Context;
- import android.net.Uri;
- import android.support.v7.widget.RecyclerView;
- import android.util.Log;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.ImageView;
- import android.widget.LinearLayout;
- import android.widget.RelativeLayout;
- import android.widget.TextView;
- import com.bumptech.glide.Glide;
- import com.bumptech.glide.Priority;
- import com.bumptech.glide.load.engine.DiskCacheStrategy;
- import com.bumptech.glide.request.RequestOptions;
- import com.why.project.photopickernewdemo.R;
- import com.why.project.photopickernewdemo.bean.PictureBean;
- import java.io.File;
- import java.util.ArrayList;
- import java.util.List;
- import static com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.withCrossFade;
- /**
- * Created by HaiyuKing
- * Used 照片网格适配器
- */
- public class PictureAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
- private static final String TAG = PictureAdapter.class.getSimpleName();
- /**上下文*/
- private Context myContext;
- /**自定义列表项标题集合*/
- private ArrayList<PictureBean> listitemList;
- final static int TYPE_ADD = 1;
- final static int TYPE_PHOTO = 2;
- public final static int MAX = 15;//总数目,这里根据实际情况设置,设置100基本上表明无限制了
- /*
- * 构造函数
- */
- public PictureAdapter(Context context, ArrayList<PictureBean> itemlist) {
- myContext = context;
- listitemList = itemlist;
- }
- /**
- * 获取总的条目数
- */
- @Override
- public int getItemCount() {
- Log.w(TAG,"{getItemCount}listitemList.size()="+listitemList.size());
- int count = listitemList.size();
- if (count > MAX) {
- count = MAX;
- }
- count = count + 1;
- return count;
- }
- @Override
- public int getItemViewType(int position) {
- Log.w(TAG,"{getItemViewType}position="+position);
- Log.w(TAG,"{getItemViewType}listitemList.size()="+listitemList.size());
- return (position == listitemList.size()) ? TYPE_ADD : TYPE_PHOTO;
- }
- /**
- * 创建ViewHolder
- */
- @Override
- public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- if(viewType == TYPE_ADD) {
- View viewfoot = LayoutInflater.from(myContext).inflate(R.layout.pic_grid_foot_item, parent, false);
- ItemFootViewHolder itemfootViewHolder = new ItemFootViewHolder(viewfoot);
- return itemfootViewHolder;
- } else if(viewType == TYPE_PHOTO) {
- View view = LayoutInflater.from(myContext).inflate(R.layout.pic_grid_item, parent, false);
- ItemViewHolder itemViewHolder = new ItemViewHolder(view);
- return itemViewHolder;
- }
- return null;
- }
- /**
- * 声明列表项ViewHolder*/
- static class ItemViewHolder extends RecyclerView.ViewHolder
- {
- public ItemViewHolder(View view)
- {
- super(view);
- griditemLayout = (LinearLayout) view.findViewById(R.id.griditemLayout);
- griditemimgLayout = (RelativeLayout) view.findViewById(R.id.griditemimgLayout);
- grid_img = (ImageView) view.findViewById(R.id.grid_img);
- grid_img_state = (TextView) view.findViewById(R.id.grid_img_state);
- }
- LinearLayout griditemLayout;
- RelativeLayout griditemimgLayout;
- ImageView grid_img;
- TextView grid_img_state;
- }
- /**
- * 声明最后一个ViewHolder*/
- static class ItemFootViewHolder extends RecyclerView.ViewHolder
- {
- public ItemFootViewHolder(View view)
- {
- super(view);
- gridfootitemLayout = (RelativeLayout) view.findViewById(R.id.gridfootitemLayout);
- }
- RelativeLayout gridfootitemLayout;
- }
- /**
- * 将数据绑定至ViewHolder
- */
- @Override
- public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int index) {
- if(viewHolder instanceof ItemViewHolder){
- PictureBean listItemModel = listitemList.get(index);
- final ItemViewHolder itemViewHold = ((ItemViewHolder)viewHolder);
- Uri uri = Uri.fromFile(new File(listItemModel.getPicPath()));
- RequestOptions options = new RequestOptions()
- //设置等待时的图片
- .placeholder(R.drawable.img_loading)
- //设置加载失败后的图片显示
- .error(R.drawable.img_error)
- //缓存策略,跳过内存缓存【此处应该设置为false,否则列表刷新时会闪一下】
- .skipMemoryCache(false)
- //缓存策略,硬盘缓存-仅仅缓存最终的图像,即降低分辨率后的(或者是转换后的)
- .diskCacheStrategy(DiskCacheStrategy.ALL)
- //设置图片加载的优先级
- .priority(Priority.HIGH);
- Glide.with(myContext)
- .load(uri)
- .apply(options)
- //默认淡入淡出动画
- .transition(withCrossFade())
- .into(itemViewHold.grid_img);
- itemViewHold.grid_img_state.setText("(" + (index+1) + "/" + listitemList.size() + ")");
- //如果设置了回调,则设置点击事件
- if (mOnItemClickLitener != null)
- {
- itemViewHold.grid_img.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- int position = itemViewHold.getLayoutPosition();//在增加数据或者减少数据时候,position和index就不一样了
- mOnItemClickLitener.onItemClick(view,position);
- }
- });
- }
- }else if(viewHolder instanceof ItemFootViewHolder){
- final ItemFootViewHolder itemFootViewHold = ((ItemFootViewHolder)viewHolder);
- //如果设置了回调,则设置点击事件
- if (mOnItemClickLitener != null)
- {
- itemFootViewHold.gridfootitemLayout.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- mOnItemClickLitener.onItemAddClick();
- }
- });
- }
- }
- }
- /**
- * 添加Item--用于动画的展现*/
- public void addItem(int position,PictureBean itemModel) {
- listitemList.add(position,itemModel);
- notifyItemInserted(position);
- }
- /**
- * 删除Item--用于动画的展现*/
- public void removeItem(int position) {
- listitemList.remove(position);
- notifyItemRemoved(position);
- }
- /*=====================添加OnItemClickListener回调================================*/
- public interface OnItemClickLitener
- {
- /**图片的点击事件*/
- void onItemClick(View view, int position);
- /**添加的点击事件*/
- void onItemAddClick();
- }
- private OnItemClickLitener mOnItemClickLitener;
- public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener)
- {
- this.mOnItemClickLitener = mOnItemClickLitener;
- }
- //返回当前图片集合的所有路径集合【用于预览】
- public List<String> getAllPhotoPaths() {
- List<String> allPhotoPaths = new ArrayList<String>(listitemList.size());
- for (PictureBean pictureBean: listitemList) {
- allPhotoPaths.add(pictureBean.getPicPath());
- }
- return allPhotoPaths;
- }
- }
(2)常规使用
- package com.why.project.photopickernewdemo;
- import android.app.Activity;
- import android.content.Intent;
- import android.os.Bundle;
- import android.support.v7.app.AppCompatActivity;
- import android.support.v7.widget.GridLayoutManager;
- import android.support.v7.widget.RecyclerView;
- import android.util.Log;
- import android.view.View;
- import android.widget.Toast;
- import com.why.project.photopickernewdemo.adapter.PictureAdapter;
- import com.why.project.photopickernewdemo.bean.PictureBean;
- import com.why.project.photopickernewdemo.utils.Globals;
- import java.util.ArrayList;
- import me.iwf.photopicker.PhotoPicker;
- import me.iwf.photopicker.PhotoPreview;
- public class MainActivity extends AppCompatActivity {
- private static final String TAG = MainActivity.class.getSimpleName();
- private RecyclerView mRecyclerView;
- private ArrayList<PictureBean> mPictureBeansList;
- private PictureAdapter mPictureAdapter;
- private ArrayList<String> selPhotosPath = null;//选中的图片路径集合
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- initViews();
- initDatas();
- initEvents();
- }
- private void initViews() {
- mRecyclerView = findViewById(R.id.picture_grid);
- }
- private void initDatas() {
- selPhotosPath = new ArrayList<String>();
- //=============图片九宫格=========================
- mPictureAdapter = null;
- mPictureBeansList = new ArrayList<PictureBean>();
- //设置布局管理器
- GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 3);
- mRecyclerView.setLayoutManager(gridLayoutManager);
- if(mPictureAdapter == null){
- //设置适配器
- mPictureAdapter = new PictureAdapter(this, mPictureBeansList);
- mRecyclerView.setAdapter(mPictureAdapter);
- //添加分割线
- //设置添加删除动画
- //调用ListView的setSelected(!ListView.isSelected())方法,这样就能及时刷新布局
- mRecyclerView.setSelected(true);
- }else{
- mPictureAdapter.notifyDataSetChanged();
- }
- }
- private void initEvents() {
- //图片九宫格点击事件
- mPictureAdapter.setOnItemClickLitener(new PictureAdapter.OnItemClickLitener() {
- @Override
- public void onItemClick(View v, int position) {
- //打开图片预览界面
- ArrayList<String> photos = (ArrayList<String>) mPictureAdapter.getAllPhotoPaths();
- PhotoPreview.builder()
- .setPhotos(photos)
- .setCurrentItem(position)
- .setShowDeleteButton(false)
- .start(MainActivity.this);
- }
- @Override
- public void onItemAddClick() {
- PhotoPicker.builder()
- .setPhotoCount(mPictureAdapter.MAX)
- .setGridColumnCount(3)
- //.setSelected(selPhotosPath)
- .start(MainActivity.this, Globals.CHOOSE_PIC_REQUEST_CODE);
- }
- });
- }
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- Log.w(TAG, "{onActivityResult}resultCode="+resultCode);
- Log.w(TAG, "{onActivityResult}requestCode="+requestCode);
- if (resultCode == Activity.RESULT_OK) {
- //选择照片
- if(requestCode == Globals.CHOOSE_PIC_REQUEST_CODE){
- if (data != null) {
- selPhotosPath = data.getStringArrayListExtra(PhotoPicker.KEY_SELECTED_PHOTOS);
- }
- if (selPhotosPath != null) {
- //下面的代码主要用于这样一个场景,就是注释了.setSelected(selPhotosPath)之后,还想要保证选择的图片不重复
- /*for(String path : selPhotosPath){
- Log.w(TAG,"path="+path);///storage/emulated/0/tempHxzk/IMG_1498034535796.jpg
- boolean existThisPic = false;
- for(int i=0;i<mPictureBeansList.size();i++){
- if(path.equals(mPictureBeansList.get(i).getPicPath())){
- //如果新选择的图片集合中存在之前选中的图片,那么跳过去
- existThisPic = true;
- break;
- }
- }
- if(! existThisPic){
- PictureBean pictureBean = new PictureBean();
- pictureBean.setPicPath(path);
- pictureBean.setPicName(getFileName(path));
- //去掉总数目的限制,这里通过增大MAX的数字来实现
- if (mPictureBeansList.size() < mPictureAdapter.MAX) {
- mPictureBeansList.add(pictureBean);
- } else {
- Toast.makeText(MainActivity.this, "最多可以选择" + mPictureAdapter.MAX + "张图片", Toast.LENGTH_SHORT).show();
- break;
- }
- }
- }*/
- //是常规操作,和上面的代码不可共存
- for (String path : selPhotosPath) {
- PictureBean pictureBean = new PictureBean();
- pictureBean.setPicPath(path);
- pictureBean.setPicName(Globals.getFileName(path));
- //去掉总数目的限制,这里通过增大MAX的数字来实现
- if (mPictureBeansList.size() < mPictureAdapter.MAX) {
- mPictureBeansList.add(pictureBean);
- } else {
- Toast.makeText(MainActivity.this, "最多可以选择" + mPictureAdapter.MAX + "张图片", Toast.LENGTH_SHORT).show();
- break;
- }
- }
- mPictureAdapter.notifyDataSetChanged();
- }
- }
- }
- }
- }
混淆配置
- # PhotoPicker混淆
- # Glide
- -keep public class * implements com.bumptech.glide.module.GlideModule
- -keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
- **[] $VALUES;
- public *;
- }
- # support-v7-appcompat
- -keep public class android.support.v7.widget.** { *; }
- -keep public class android.support.v7.internal.widget.** { *; }
- -keep public class android.support.v7.internal.view.menu.** { *; }
- -keep public class * extends android.support.v4.view.ActionProvider {
- public <init>(android.content.Context);
- }
- # support-design
- -dontwarn android.support.design.**
- -keep class android.support.design.** { *; }
- -keep interface android.support.design.** { *; }
- -keep public class android.support.design.R$* { *; }
参考资料
项目demo下载地址
https://github.com/haiyuKing/PhotoPickerNewDemo
PhotoPickerNewDemo【PhotoPicker0.9.12的个性化修改以及使用(内部glide版本号是4.1.1)】的更多相关文章
- PhotoPickerDemo【PhotoPicker0.9.8的个性化修改以及使用(内部glide版本号是3.7.0)】
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 本Demo使用的是PhotoPicker 0.9.8版本,属于比较旧的版本,里面集成的glide版本号是3.7.0.本篇文章主要是留 ...
- Ubuntu 12/14 个性化配置
计算机名:jianbao-pc 用户名:jianbao 修改 /opt目录的 用户名 及 用户组 : sudo chown -R jianbao:jianbao /opt Ubuntu 如何开启 ...
- 修改AssemblyInfo.cs自动生成版本号
一. 版本号自动生成方法 1.把 AssemblyInfo.cs文件中的[assembly:AssemblyVersion("1.0.0.0")]改成[assembly:Assem ...
- nginx.conf(centos6, 1.12)主配置文件修改
#nginx1.12 centos6.xuser admin admin;worker_processes 4; error_log /data/services/logs/nginx_error.l ...
- MySQL8.0.12版本密码修改策略问题
查看密码策略(修改临时密码之后才可查看) show variables like 'validate_password%'; 8之前 validate_password_ 8之后validat ...
- STS IDE 个性化修改
JDK: Eclipse或MyEclipse文件系统不同步的解决方法 STS汉化: 1.解压STS中的language文件夹 以我的安装目录为例,我的STS的安装在D:盘下.将解压后的“languag ...
- 个性化修改Linux登录时的字符界面
如果采用root账号登录编辑/etc/bashrc内容,那所有其他帐号登录都会提示相同的内容,如果想每个用户进行配置,那就去每个帐号的目录下去配置吧. 这里提供改一个文件所有帐号都能看到的个性显示内容 ...
- android studio 汉化 美化 个性化 修改 安卓工作室 2.3.3 最新版
韩梦飞沙 韩亚飞 313134555@qq.com yue31313 han_meng_fei_sha 先看一下效果. 建议全屏看图,或者新标签看图.
- Nginx修改版本信息或隐藏版本号
一,隐藏版本号.首先说明,这个是某一方面隐藏,不是彻底隐藏.未隐藏之前查看nginx信息: 隐藏方法: 修改nginx.conf配置文件,在http { } 标签里边加入字段: server_toke ...
随机推荐
- spring boot整合shiro
安全框架Shiro和Spring Security比较,本文主要围绕Shiro进行学习 一 Shiro 是一个强大而灵活的开源安全框架,能够清晰的处理认证 授权 管理会话以及,密码加密 01 .认证与 ...
- 各位情人节快乐, Python帮忙撒狗粮, 我连夜做了这个程序!
阅读本文大概需要5分钟 码农的情人节 一年一度的情人节要来啦,这个浪漫温馨的节日,走在大街小巷,走在地铁里,走在商场里,走在电影院,姑娘们手里几乎都捧着一束花,心里都是乐滋滋的,一脸幸福的样子,忽然想 ...
- eclipse下搭建hibernate5.0环境
hibernate引入的jar包:hibernate-release-5.0.12.Final.zip 数据库驱动:mysql-connector-java-5.1.46 二.安装hibernate插 ...
- grpc.go
package,,), etcd.WithPrefix(), etcd.WithPrevKV()} gw.wch = gw.c.Watch(gw.ctx, gw.target, opts... ...
- Python初学者必看(1)
python介绍 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚本解释程序,作为ABC语言 ...
- CISP-PTE注册信息安全专业人员渗透测试工程师知识体系大纲
CISP-PTE注册信息安全专业人员渗透测试工程师知识体系大纲 都是图.. 不足之处,欢迎补充
- java.lang.NoSuchMethodError: org.springframework.boot.builder.SpringApplicationBuilder.<init>([Ljava
搭建spring cloud的时候,报以下错误: java.lang.NoSuchMethodError: org.springframework.boot.builder.SpringApplica ...
- 【SAP S/4 1511之变】:主数据之变
本博文主要讲述SAP S/4 1511版本的变化,主要是跟ECC版本的对比.变化还是挺多的,相当一部分是后勤,但绝大部分还是财务成本这一块.作为从事S/4版本的从业者,了解1511版本的变化还是挺有必 ...
- C/C++反三角函数使用注意
最近写的东西用到了数学库中的acos函数,但是代码在运行的时候有时候会出莫名其妙的错误,比如返回值是个特别大的数. 最后在debug 的时候发现acos返回的数据很奇怪,但是传入的参数明明没有问题,可 ...
- 聚焦“云开发圆桌论坛”,大前端Serverless大佬们释放了这些讯号!
4月14日,由云加社区举办的TVP&腾讯云技术交流日云开发专场,暨"腾讯云-云开发圆桌论坛"在北京.深圳两地同步举行. 当天下午,一场主题为"基于大前端和node ...