本地图片选择器(picasso框架)

要点:

1.使用picasso框架,只需导入jar包

Picasso.with(mContext).load(R.drawable.picture_unselected).into((ImageView)mHolder.ibt);

2.在子线程里扫描系统图片

3.获得文件修改时间:file.lastModified()//long类型

4.Set无序且不重复!获取set的值

mDirPaths = new HashSet<String>();
Iterator<String> i = mDirPaths.iterator();
while(i.hasNext()) {
i.next();// 值
}

5.list1 = list2 (难点)
问题描述:

                // adapter = new ImageAdapter(this,paths);
               // mGridView.setAdapter(adapter);
              // paths和selectPaths都是list
                 paths.clear();           //1.
                 paths = selectPaths;     //2.
                 for (String p : paths) { //3.
                    Log.v("TAG", p);
                }
                adapter.notifyDataSetChanged(); // 4.         

//  步骤3.根据打印结果,可以打印出值
//  步骤4.但是adapet通知的时候,显示出来的数据为空(即paths不存在值)
//  显然有点矛盾
//  我的理解是,adapter适配的是适配堆内存,path一开始指向的就是这个堆
//  内存。然后步骤1.paths.clear()将堆内存清空,之后步骤2.让paths
//  指向别的堆内存。在步骤4.适配器通知的时候,依然是指向之前的堆内存
//  (被清空),所以造成了看起来paths没有数据,然而循环打印paths却能
//   打印出值,这一矛盾的现象。

//              这里的解决方案是
//              2.测试代码~(正确事例)
//              paths.clear();
//              for (String p : selectPaths) {
//                  paths.add(p);
//              }
//              adapter.notifyDataSetChanged();

6.Viewholder的声明,设置点击监听的时候,如果Viewholder声明为全局变量,那么mHolder.ibt设置背景的时候会设置到别的item上去了。
这里在每次getView()时声明一个Viewholder可以解决。

7.接着6的案例,选中一个item时,滑动屏幕时,别的item也会被选中,这里的解决方案是getView()的时候图片全部设置为没被选中(初始状态),然后再点击监听里设置,如果选择则将图片路径作为tag存储在list里面,然后根据当前item的路径是否在list里面,有的话则设置图片为选择状态。


说明:

1.读取读取所有的本地图片
2.使用picasso加载图片
3.图片按修改时间排序(新修改的图片会在前面)


效果

这里写图片描述


代码

activity

package com.example.testpacasso;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import android.app.Activity;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.GridView;

public class MainActivity extends Activity {
    private GridView mGridView;
    private ImageAdapter adapter;
    // 图片路径, 有序
    private List<String> paths;
    // 扫描到的图片路径, 无序且不重复
    private Set<String> mDirPaths ;
    private Handler mHandler;
    private Button mButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mHandler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                adapter.notifyDataSetChanged();
            }
        };
        initViews();
        initDatas();
        initEvent();
    }

    private void initEvent() {
        mButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // 获取选择图片的路径
                List<String> selectPaths = adapter.getSelectPaths();

                // 拿到图片路径之后根据自己的需求做处理
                // 。。。。。


                //  1.测试代码(显示空白,看起来paths没有值)
                //  并且在adapter.notifyDataSetChanged();往下的代码都不会执行!但又没有异常抛出.
//              paths.clear();
//              paths = selectPaths;
//              for (String p : paths) {
//                  Log.v("TAG", p);
//              }
//              adapter.notifyDataSetChanged();

                // 2.测试代码~(正确事例)
//              paths.clear();
//              for (String p : selectPaths) {
//                  paths.add(p);
//              }
//              for (String p : paths) {
//                  Log.v("TAG", p);
//              }
//              adapter.notifyDataSetChanged();
            }
        });

    }


    private void initViews() {
        mGridView = (GridView) findViewById(R.id.gv);
        mButton = (Button) findViewById(R.id.bt);
    }

    private void initDatas() {
        // 获得图片的路径
        paths = new ArrayList<String>();
        adapter = new ImageAdapter(this,paths);
        mGridView.setAdapter(adapter);
        // 扫描图片
        getImagePath();
    }


    private void getImagePath() {
        // 开启线程查找图片
        new Thread(new Runnable() {

            @Override
            public void run() {
                // 1.所有图片的Uri
                Uri mImgUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                // 2.
                ContentResolver cr = MainActivity.this.getContentResolver();
                // 3.
                Cursor cursor = cr.query(mImgUri, null,
                        MediaStore.Images.Media.MIME_TYPE + "= ? or "
                                + MediaStore.Images.Media.MIME_TYPE + "= ?",
                        new String[] { "image/jpeg", "image/png" },
                        MediaStore.Images.Media.DATE_MODIFIED);
                // 4.
                mDirPaths = new HashSet<String>();
                while(cursor.moveToNext()) {
                    String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
                    mDirPaths.add(path);
                }

                // 遍历set
                Iterator<String> i = mDirPaths.iterator();
                // 存储模型数据
                List<ImageModel> mList = new ArrayList<ImageModel>();
                ImageModel imageModel = null;
                File file = null;
                String path ;
                while (i.hasNext()) {
                    imageModel = new ImageModel();
                    path = i.next();
                    imageModel.setPath(path);
                    file = new File(path);
                    imageModel.setMotifyTime(file.lastModified());
                    mList.add(imageModel);
                }
                // 按修改时间排序
                // 创建时间数组
                int length = mList.size();
                long [] motify = new long[length];
                for (int j = 0;j < length; j++) {
                    motify[j] = mList.get(j).getMotifyTime();
                }
                // 快排排序
                quickSort(motify,0,length-1);
                // 根据排序,重新排序path(升序排列)
                paths.clear();
                for (int k = 0; k < length; k++) {
                    for (int p = 0; p < mList.size(); p++) {
                        if (mList.get(p).getMotifyTime() == motify[k]) {
                            paths.add(mList.get(p).getPath()); //移除,避免修改时间相同的实体
                            mList.remove(p);
                            break;
                        }
                    }
                }
                // paths倒序排序
                Collections.reverse(paths);

                // handle
                mHandler.sendEmptyMessage(0);

            }
        }).start();

    }


    // 快排1
    private static void quickSort(long[] array,int beg,int end){  
        if(beg >= end || array == null)  
            return;  
        int p = partition(array, beg, end);  
        quickSort(array, beg, p-1);  
        quickSort(array, p+1, end);  
    }  
    // 快排2
    private static int partition(long[] array,int beg,int end){  
        long last = array[end];  
        int i = beg -1;  
        for (int j = beg; j <= end-1; j++) {  
            if(array[j] <= last){  
                i++;  
                if(i != j){  
                    array[i] = array[i]^array[j];  
                    array[j] = array[i]^array[j];  
                    array[i] = array[i]^array[j];  
                }  
            }  
        }  
        if((i+1) != end){  
            array[i+1] = array[i+1]^array[end];  
            array[end] = array[i+1]^array[end];  
            array[i+1] = array[i+1]^array[end];  
        }  
        return i+1;  
    }  


}

adapter

package com.example.testpacasso;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import com.squareup.picasso.Picasso;

import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.RelativeLayout;

public class ImageAdapter extends BaseAdapter{
    private Context mContext;
    private List<String> paths;
    private View view;
//  private ViewHolder mHolder;  // 如果设置为全局变量,在点击监听部分会有与预期不符合的效果!
    // 选中图片列表
    private List<String> selectPaths;


    public ImageAdapter(Context mContext, List<String> paths) {
        this.mContext = mContext;
        this.paths = paths;
        selectPaths = new ArrayList<String>();
    }

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

    @Override
    public Object getItem(int position) {
        return paths.get(position);
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final int pos = position;
        final ViewHolder mHolder;

        if (convertView == null) {
            view = LayoutInflater.from(mContext).inflate(R.layout.item, null); // 设置parent崩溃
            mHolder = new ViewHolder();
            mHolder.img = (ImageView) view.findViewById(R.id.iv);
            mHolder.ibt = (ImageButton) view.findViewById(R.id.ib);
            view.setTag(mHolder);
        } else {
            view = convertView;
            mHolder = (ViewHolder) view.getTag();
        }

        // 加载图片
        Picasso.with(mContext).load(new File(paths.get(position))).placeholder(R.drawable.ic_launcher).resize(500, 500)
          .centerCrop().into(mHolder.img);

        // 重置状态
        Picasso.with(mContext).load(R.drawable.picture_unselected).into((ImageView)mHolder.ibt);
        // 如果被选择,则改为选中状态
        if (selectPaths.contains(paths.get(pos))) {
            Picasso.with(mContext).load(R.drawable.pictures_selected).into((ImageView) mHolder.ibt);
        }

        // 点击图片打钩图片
        mHolder.ibt.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                if (!selectPaths.contains(paths.get(pos))) {
                    Picasso.with(mContext).load(R.drawable.pictures_selected).placeholder(R.drawable.picture_unselected).into((ImageView)mHolder.ibt);
                    selectPaths.add(paths.get(pos));
                } else {
                    Picasso.with(mContext).load(R.drawable.picture_unselected).into((ImageView)mHolder.ibt);
                    selectPaths.remove(paths.get(pos));
                }
            }
        });

        return view;
    }


     class ViewHolder {
         ImageView img;
         ImageButton ibt;
     } 

     // 得到选中的图片
     public List<String> getSelectPaths() {
        return selectPaths;
     }

}

main_xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
 >
 <LinearLayout 
     android:layout_width="match_parent"
     android:layout_height="40dp"
     android:id="@+id/ll"
     android:background="#2294D4">

     <TextView 
         android:layout_width="0dp"
         android:layout_height="match_parent"
         android:layout_weight="8"
         android:text="图片选择器"
         android:gravity="center|left"
         android:paddingLeft="10dp"
         android:textColor="#fff"
         android:textSize="20dp"/>

     <Button 
         android:layout_width="0dp"
         android:layout_height="match_parent"
         android:layout_weight="2"
         android:textColor="#fff"
         android:text="确定"
         android:id="@+id/bt"/>
 </LinearLayout>


    <GridView 
        android:layout_below="@+id/ll"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:numColumns="3"
        android:id="@+id/gv"/>

</RelativeLayout>

item.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
     >

    <ImageView
        android:id="@+id/iv"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:layout_margin="1dp"
        android:scaleType="centerCrop"
         />

    <ImageButton
        android:id="@+id/ib"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_marginRight="3dp"
        android:layout_marginTop="3dp"
        android:background="@null"
        android:src="@drawable/picture_unselected" />

</RelativeLayout>

ImageModel

package com.example.testpacasso;

public class ImageModel{
    // 路径
    private String path;
    // 修改时间
    private long motifyTime;


    public String getPath() {
        return path;
    }
    public void setPath(String path) {
        this.path = path;
    }
    public long getMotifyTime() {
        return motifyTime;
    }
    public void setMotifyTime(long motifyTime) {
        this.motifyTime = motifyTime;
    }



}

权限:

  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>

参考:http://blog.csdn.net/u010542146/article/details/50766471
还有网上的一些例子。


2016/06/01 更新

修改adapter类,添加点击事件,点击图片跳转至图片放大页面,可以左右滑动


ImageAdapter

package com.example.testpacasso;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import com.squareup.picasso.Picasso;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageButton;
import android.widget.ImageView;

public class ImageAdapter extends BaseAdapter{
    private Context mContext;
    private List<String> paths;
    private View view;
//  private ViewHolder mHolder;  // 如果设置为全局变量,在点击监听部分会有与预期不符合的效果!
    // 选中图片列表
    private List<String> selectPaths;


    public ImageAdapter(Context mContext, List<String> paths) {
        this.mContext = mContext;
        this.paths = paths;
        selectPaths = new ArrayList<String>();
    }

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

    @Override
    public Object getItem(int position) {
        return paths.get(position);
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final int pos = position;
        final ViewHolder mHolder;

        if (convertView == null) {
            view = LayoutInflater.from(mContext).inflate(R.layout.item, null); // 设置parent崩溃
            mHolder = new ViewHolder();
            mHolder.img = (ImageView) view.findViewById(R.id.iv);
            mHolder.ibt = (ImageButton) view.findViewById(R.id.ib);
            view.setTag(mHolder);
        } else {
            view = convertView;
            mHolder = (ViewHolder) view.getTag();
        }

        // 加载图片
        Picasso.with(mContext).load(new File(paths.get(position))).placeholder(R.drawable.ic_launcher).resize(500, 500)
          .centerCrop().into(mHolder.img);

        // 重置状态
        Picasso.with(mContext).load(R.drawable.picture_unselected).into((ImageView)mHolder.ibt);
        // 如果被选择,则改为选中状态
        if (selectPaths.contains(paths.get(pos))) {
            Picasso.with(mContext).load(R.drawable.pictures_selected).into((ImageView) mHolder.ibt);
        }

        // 点击图片打钩图片
        mHolder.ibt.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                if (!selectPaths.contains(paths.get(pos))) {
                    Picasso.with(mContext).load(R.drawable.pictures_selected).placeholder(R.drawable.picture_unselected).into((ImageView)mHolder.ibt);
                    selectPaths.add(paths.get(pos));
                } else {
                    Picasso.with(mContext).load(R.drawable.picture_unselected).into((ImageView)mHolder.ibt);
                    selectPaths.remove(paths.get(pos));
                }
            }
        });

        // 點擊放大
        mHolder.img.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                Intent intent = new Intent(mContext, ImageActivity.class);
                Bundle bundle = new Bundle();
                ArrayList<String> arrayList = (ArrayList<String>) paths;
                bundle.putStringArrayList(ImageActivity.EXTRA_URLS, arrayList);
                bundle.putInt(ImageActivity.EXTRA_POSITION,pos);
                intent.putExtra(ImageActivity.EXTRA_BUNDLE, bundle);
                mContext.startActivity(intent);
            }
        });

        return view;
    }


     class ViewHolder {
         ImageView img;
         ImageButton ibt;
     } 

     // 得到选中的图片
     public List<String> getSelectPaths() {
        return selectPaths;
     }

}

ImageActivity

package com.example.testpacasso;

import java.io.File;
import java.util.ArrayList;

import com.squareup.picasso.Picasso;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

/**
 * 
 * @author yj<br>
 * 要使用这个类,必须传入一个包含图片路径的集合和要显示图片的位置position<br>
 * 该类可以左右滑动显示图片<br>
 */
public class ImageActivity extends Activity {

    private ViewPager mViewPager;
    /**
     * 当前图片的位置,作为显示的入口
     */
    private int position;
    private PagerAdapter mAdapter;
    /**
     * 存放要显示图片的路径集合
     */
    private ArrayList<String> paths;
    /**
     * 存放ViewPager Item的下标,用户removeView时的判断依据
     */
    private ArrayList<Integer> arrayList;
    /**
     *  ViewPager是否在向左滑动
     */
    private boolean isLeft;
    /**
     * 临时存放的变量,用于判断ViewPager是向左滑动还是向右滑动
     */
    private int temp;
    /**
     * 屏幕的长
     */
    private int screenWidth;
    /**
     * 屏幕的寬
     */
    private int screenHeight;

    public static String EXTRA_BUNDLE ="bundle";
    public static String EXTRA_URLS ="urls";
    public static String EXTRA_POSITION ="position";


    @SuppressWarnings("unchecked")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_image);

        init();
        initEvent();
    }

    private void init() {
        screenWidth = getWindowManager().getDefaultDisplay().getWidth();
        screenHeight = getWindowManager().getDefaultDisplay().getHeight();

        arrayList = new ArrayList<Integer>();

        // 获取数据,包括图片路径集合和当前图片路径所在的下标
        Bundle bundle = getIntent().getBundleExtra(EXTRA_BUNDLE);
        if (bundle != null) {
            paths = (ArrayList<String>) bundle.get(EXTRA_URLS);
            position = bundle.getInt(EXTRA_POSITION);
        }

        mViewPager = (ViewPager) findViewById(R.id.id_viewpager);
        mAdapter = new PagerAdapter() {

            @Override
            public void destroyItem(ViewGroup container, int position,
                    Object object) {
                if (isLeft) {
                    // 左滑
                    container.removeViewAt(findSmallIndex());
                    arrayList.remove(findSmallIndex());
                } else {
                    // 右滑
                    container.removeViewAt(findBigIndex());
                    arrayList.remove(findBigIndex());
                }

            }

            @Override
            public Object instantiateItem(ViewGroup container, int position) {
                View view = LayoutInflater.from(ImageActivity.this).inflate(R.layout.image, null);
                ImageView imageView = (ImageView) view.findViewById(R.id.iv_image);
                String url = paths.get(position);
                // 1.使用picasso 效果很好
                Picasso.with(ImageActivity.this).load(new File(url)).centerInside().resize(screenWidth, screenHeight).into(imageView);
//              // 2.使用异步加载, 效果一般, 不够picasso好
//              MyTask myTask = new MyTask(imageView);
//              myTask.execute(url, calculateInSampleSize(url)+"");
                container.addView(view);
                arrayList.add(position);
                return view;
            }

            @Override
            public boolean isViewFromObject(View arg0, Object arg1) {
                return arg0 == arg1;
            }

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

        mViewPager.setAdapter(mAdapter);
        // 显示当前的图片
        // 此刻ViewPager只会加载position前后的内容,即只有3个View
        mViewPager.setCurrentItem(position);

    }

    private void initEvent() {
        // 判断是手指像左滑动还是像右滑动
                mViewPager.setOnPageChangeListener(new OnPageChangeListener() {

                    @Override
                    public void onPageSelected(int arg0) {
                    }

                    @Override
                    public void onPageScrolled(int arg0, float arg1, int arg2) {
                        // 经过测试发现
                        // arg2在向左滑动时,arg2会不断增大,最后变为0,
                        // arg2在向右滑动时,arg2会不断减小,最后变为0,
                        if (arg2 != 0) {
                            temp = arg2;
                        } else {
                            if (temp > 300) {
                                isLeft = true;
                            } else {
                                isLeft = false;
                            }
                        }
                    }

                    @Override
                    public void onPageScrollStateChanged(int arg0) {
                    }
                });
    }

    /**
     * 找到列表最小item所在的小标
     * @return
     */
    protected int findSmallIndex() {
        int index = 0;
        for (int i = 1; i < arrayList.size(); i++) {
            if (arrayList.get(index) > arrayList.get(i)) {
                index = i;
            }
        }
        return index;
    }

    /**
     * 找到列表里最大item所在的下标
     * @return
     */
    protected int findBigIndex() {
        int index = 0;
        for (int i = 1; i < arrayList.size(); i++) {
            if (arrayList.get(index) < arrayList.get(i)) {
                index = i;
            }
        }
        return index;
    }



    /**
     *  没有使用到, 作为记录 
     */ 
//  /**
//   * 计算合适的inSampleSize
//   * 
//   * @param url
//   * @param width
//   * @param height
//   * @return
//   */
//  private int calculateInSampleSize(String url) {
//      Options options = new Options();
//      options.inJustDecodeBounds = true;
//      int inSampleSize = 1;
//      BitmapFactory.decodeFile(url, options);
//      int bitmapWidth = options.outWidth;
//      int bitmapheight = options.outHeight;
//
//      while (bitmapWidth / inSampleSize > screenWidth
//              && bitmapheight / inSampleSize > screenHeight) {
//          inSampleSize = inSampleSize * 2;
//      }
//      return inSampleSize;
//  }

    /**
     *  没有使用到, 作为记录 
     */
//      /**
//       * 异步,防止卡顿
//       * @author yj
//       *
//       */
//      class MyTask extends AsyncTask<String, Void, Bitmap> {
//          private ImageView view;
//          public MyTask(ImageView view) {
//              this.view = view;
//          }
    //
//          @Override
//          protected Bitmap doInBackground(String... params) {
//              Options options = new Options();
//              options.inSampleSize = Integer.parseInt(params[1]);
//              Bitmap bitmap = BitmapFactory.decodeFile(params[0], options);
//              return bitmap;
//          }
//          
//          @Override
//          protected void onPostExecute(Bitmap result) {
//              super.onPostExecute(result);
//              view.setImageBitmap(result);
//          }
//          
//      }

}

activity_image.xml

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:background="#000" >

    <android.support.v4.view.ViewPager
        android:id="@+id/id_viewpager"
        android:layout_height="match_parent"
        android:layout_width="match_parent">

    </android.support.v4.view.ViewPager>


</RelativeLayout>

image

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
     xmlns:android="http://schemas.android.com/apk/res/android" >

    <ImageView 
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/iv_image"
        />


</RelativeLayout>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值