在做项目时常常会遇到选择本地图片的需求。曾经都是懒得写直接调用系统方法来选择图片。可是这样并不能实现多选效果。近期又遇到了,所以还是写一个demo好了。以后也方便使用。还是首先来看看效果

显示的图片使用RecyclerView实现的,利用Glide来载入;以下弹出的图片目录效果是採用PopupWindow实现,这里比採用PopupWindow更方便,弹出显示的左边图片是这个目录里的第一张图片;选中的图片能够进行预览,使用网上一个大神写的来实现的;至于图片的获取是用ContentProvider。

看看主界面的布局文件。上面一栏是一个返回button和一个跳转预览界面的button。依据是否有选中的图片来设置它的点击和显示状态。中间就是一个用于显示图片的RecyclerView,左下角是显示目录的名字可点击切换。右下角就是确定button。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
tools:context="com.cdxsc.imageselect_y.ImageSelecteActivity"> <RelativeLayout
android:layout_width="match_parent"
android:layout_height="45dp"
android:background="@android:color/white"> <ImageButton
android:id="@+id/ib_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:background="@mipmap/action_bar_back_normal" /> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@id/ib_back"
android:text="选择图片"
android:textColor="#000"
android:textSize="16sp" /> <TextView
android:id="@+id/tv_preview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="10dp"
android:enabled="false"
android:text="预览"
android:textColor="#BEBFBF"
android:textSize="16sp" />
</RelativeLayout> <View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="#eeeeee" /> <android.support.v7.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"></android.support.v7.widget.RecyclerView> <RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp"> <TextView
android:id="@+id/tv_allPic"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:clickable="true"
android:gravity="center_vertical"
android:text="全部图片"
android:textColor="@android:color/black"
android:textSize="16sp" /> <Button
android:id="@+id/bt_confirm"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="10dp"
android:background="@drawable/shape_disable"
android:enabled="false"
android:text="确定"
android:textColor="#676767"
android:textSize="16sp" />
</RelativeLayout>
</LinearLayout>

好了。如今看主界面的代码

public class ImageSelecteActivity extends AppCompatActivity {

    private static final String TAG = "lzy";
@BindView(R.id.ib_back)
ImageButton mButtonBack;
@BindView(R.id.tv_preview)
TextView mTextViewPreview;
@BindView(R.id.rv)
RecyclerView mRecyclerView;
@BindView(R.id.tv_allPic)
TextView mTextViewAllPic;
@BindView(R.id.bt_confirm)
Button mButtonConfirm;
private GalleryPopupWindow mPopupWindow;
//存储每一个目录下的图片路径,key是文件名称
private Map<String, List<String>> mGroupMap = new HashMap<>();
private List<ImageBean> list = new ArrayList<>();
//当前目录显示的图片路径
private List<String> listPath = new ArrayList<>();
//所选择的图片路径集合
private ArrayList<String> listSelectedPath = new ArrayList<>(); private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
//扫描完毕后
getGalleryList();
listPath.clear();
listPath.addAll(mGroupMap.get("全部图片"));
adapter.update(listPath);
if (mPopupWindow != null)
mPopupWindow.notifyDataChanged();
}
};
private ImageSelectAdapter adapter; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_selecte);
ButterKnife.bind(this);
init();
} private void init() {
getImages();
mRecyclerView.setLayoutManager(new GridLayoutManager(ImageSelecteActivity.this, 3));
adapter = new ImageSelectAdapter(this, listPath);
mRecyclerView.setAdapter(adapter);
adapter.setOnCheckedChangedListener(onCheckedChangedListener);
} @OnClick({R.id.ib_back, R.id.tv_preview, R.id.tv_allPic, R.id.bt_confirm})
public void onClick(View view) {
switch (view.getId()) {
case R.id.ib_back:
finish();
break;
case R.id.tv_preview://跳转预览界面
Intent intent = new Intent(ImageSelecteActivity.this, ImagePreviewActivity.class);
//把选中的图片集合传入预览界面
intent.putStringArrayListExtra("pic", listSelectedPath);
startActivity(intent);
break;
case R.id.tv_allPic://选择图片目录
if (mPopupWindow == null) {
//把目录列表的集合传入显示
mPopupWindow = new GalleryPopupWindow(this, list);
mPopupWindow.setOnItemClickListener(new GalleryPopupWindow.OnItemClickListener() {
@Override
public void onItemClick(String fileName) {
//切换了目录。清除之前的选择的信息
setButtonDisable();
listPath.clear();
listSelectedPath.clear();
//把当前选择的目录内图片的路径放入listPath,更新界面
listPath.addAll(mGroupMap.get(fileName));
adapter.update(listPath);
mTextViewAllPic.setText(fileName);
}
});
}
mPopupWindow.showAtLocation(mRecyclerView, Gravity.BOTTOM, 0, dp2px(50, ImageSelecteActivity.this));
break;
case R.id.bt_confirm://确定
for (int i = 0; i < listSelectedPath.size(); i++) {
//这里可通过Glide把它转为Bitmap
Glide.with(this).load("file://" + listSelectedPath.get(i)).asBitmap().into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
Log.i(TAG, "onResourceReady: " + resource);
}
});
}
break;
}
} /**
* dp转px
*/
public static int dp2px(int dp, Context context) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
context.getResources().getDisplayMetrics());
} //选择图片变化的监听
private ImageSelectAdapter.OnCheckedChangedListener onCheckedChangedListener = new ImageSelectAdapter.OnCheckedChangedListener() {
@Override
public void onChanged(boolean isChecked, String path, CheckBox cb, int position) {
if (isChecked) {//选中
if (listSelectedPath.size() == 9) {
Toast.makeText(ImageSelecteActivity.this, "最多选择9张图片", Toast.LENGTH_SHORT).show();
//把点击变为checked的图片变为没有checked
cb.setChecked(false);
adapter.setCheckedBoxFalse(position);
return;
}
//选中的图片路径加入集合
listSelectedPath.add(path); } else {//取消选中
//从集合中移除
if (listSelectedPath.contains(path))
listSelectedPath.remove(path);
}
//假设没有选中的button不可点击
if (listSelectedPath.size() == 0) {
setButtonDisable();
} else {
setButtonEnable();
}
}
}; //选中图片时的button状态
private void setButtonEnable() {
mButtonConfirm.setBackgroundResource(R.drawable.selector_bt);
mButtonConfirm.setTextColor(Color.parseColor("#ffffff"));
mButtonConfirm.setEnabled(true);
mTextViewPreview.setEnabled(true);
mTextViewPreview.setTextColor(getResources().getColor(R.color.colorAccent));
mButtonConfirm.setText("确定" + listSelectedPath.size() + "/9");
} //没有选择时button状态
private void setButtonDisable() {
mButtonConfirm.setBackgroundResource(R.drawable.shape_disable);
mButtonConfirm.setTextColor(Color.parseColor("#676767"));
mButtonConfirm.setEnabled(false);
mTextViewPreview.setEnabled(false);
mTextViewPreview.setTextColor(Color.parseColor("#BEBFBF"));
mButtonConfirm.setText("确定");
} /**
* 利用ContentProvider扫描手机中的图片。此方法在执行在子线程中
*/
private void getImages() {
new Thread(new Runnable() { @Override
public void run() {
Uri mImageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
ContentResolver mContentResolver = ImageSelecteActivity.this.getContentResolver();
//仅仅查询jpeg和png的图片
// Cursor mCursor = mContentResolver.query(mImageUri, null,
// MediaStore.Images.Media.MIME_TYPE + "=? or "
// + MediaStore.Images.Media.MIME_TYPE + "=? or " + MediaStore.Images.Media.MIME_TYPE + "=?",
// new String[]{"image/jpeg", "image/png", "image/jpg"}, MediaStore.Images.Media.DATE_MODIFIED);
Cursor mCursor = mContentResolver.query(mImageUri, null, null, null,
MediaStore.Images.Media.DATE_MODIFIED);
if (mCursor == null) {
return;
}
//存放全部图片的路径
List<String> listAllPic = new ArrayList<String>();
while (mCursor.moveToNext()) {
//获取图片的路径
String path = mCursor.getString(mCursor
.getColumnIndex(MediaStore.Images.Media.DATA)); //获取该图片的父路径名
String parentName = new File(path).getParentFile().getName();
listAllPic.add(path); //依据父路径名将图片放入到mGruopMap中
if (!mGroupMap.containsKey(parentName)) {
List<String> chileList = new ArrayList<String>();
chileList.add(path);
mGroupMap.put(parentName, chileList);
} else {
mGroupMap.get(parentName).add(path);
}
}
//加入全部图片
mGroupMap.put("全部图片", listAllPic);
//通知Handler扫描图片完毕
mHandler.sendEmptyMessage(0);
mCursor.close();
}
}).start(); } //获取相冊目录列表
private void getGalleryList() {
Iterator<Map.Entry<String, List<String>>> iterator = mGroupMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, List<String>> next = iterator.next();
ImageBean imageBean = new ImageBean();
imageBean.setFileName(next.getKey());
imageBean.setFirstPicPath(next.getValue().get(0));
imageBean.setCount(next.getValue().size());
if (next.getKey().equals("全部图片"))
list.add(0, imageBean);
else
list.add(imageBean);
}
}
}

·mGroupMap:这个是以目录名为key,目录内的图片路径集合为value,也就是依照目录来分别存储了全部图片的路径。

·listPath:保存的是当前显示在界面上的目录内的图片路径集合

·listSelectedPath:保存用户选中的图片路径

·list:保存的是ImageBean的集合。ImageBean保存了目录名、里面首张图片的路径以及里面所包括图片的数量,当切换目录时用于显示

·getImages():这种方法就是用来扫描手机里图片并保存的,这是在子线程中执行的,显示这可能是一个耗时的任务。通过ContentProvider获取到一个包括全部图片的Cursor,然后遍历这个Cursor把所需的数据就保存在mGroupMap里面,最后利用Handler通知界面更新。
·getGalleryList():这种方法就是mGroupMap里面的数据来给list赋值,也就是产生一个现实目录列表所需的数据集合。

·GalleryPopupWindow也就是我们用于显示文件列表的,在67--84行就是一些GalleryPopupWindow的设置,调用showAtLocation方法把PopupWindow显示在距离底部50dp的位置,并设置了点击的回调,当切换了一个目录后要做的相关操作就在这里进行。GalleryPopupWindow再待会再详细看看

接下来再看看中间RecyclerView的Adapter

public class ImageSelectAdapter extends RecyclerView.Adapter<ImageSelectAdapter.NViewHolder> {

    private Context context;
private List<String> list = new ArrayList<>();
private OnCheckedChangedListener onCheckedChangedListener;
private List<Boolean> listChecked = new ArrayList<>(); public ImageSelectAdapter(Context context, List<String> list) {
this.context = context;
this.list.addAll(list);
setListCheched(list);
} public void update(List<String> list) {
this.list.clear();
this.list.addAll(list);
setListCheched(list);
notifyDataSetChanged(); } /**
* 设置listChecked的初始值
*
* @param list
*/
private void setListCheched(List<String> list) {
listChecked.clear();
for (int i = 0; i < list.size(); i++) {
listChecked.add(false);
}
} //当点击超过了九张图片,再点击的设置为false
public void setCheckedBoxFalse(int pos) {
listChecked.set(pos, false);
} public interface OnCheckedChangedListener {
/**
* @param isChecked 是否选中
* @param path 点击的图片路径
* @param cb 点击的CheckBox
* @param pos 点击的位置
*/
void onChanged(boolean isChecked, String path, CheckBox cb, int pos);
} public void setOnCheckedChangedListener(OnCheckedChangedListener onCheckedChangedListener) {
this.onCheckedChangedListener = onCheckedChangedListener;
} @Override
public NViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new NViewHolder(LayoutInflater.from(context).inflate(R.layout.item_image_select, parent, false));
} @Override
public void onBindViewHolder(final NViewHolder holder, final int position) {
Glide.with(context).load("file://" + list.get(position)).into(holder.iv);
holder.cb.setChecked(listChecked.get(position));
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
holder.cb.setChecked(!holder.cb.isChecked());
if (holder.cb.isChecked()) {
listChecked.set(position, true);
} else {
listChecked.set(position, false);
}
if (onCheckedChangedListener != null) {
onCheckedChangedListener.onChanged(holder.cb.isChecked(), list.get(position), holder.cb, position);
}
}
});
} @Override
public int getItemCount() {
return list.size();
} public class NViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.iv_itemImageSelect)
ImageView iv;
@BindView(R.id.cb_itemImageSelect)
CheckBox cb; public NViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
} }

这里Item的布局文件就是一个ImageView加一个CheckBox。依据选中状态改变CheckBox的状态,这里就不贴出来了。

·listChecked:这个集合是用来存储每一个位置是否Check的,假设在onBindViewHolder里面不设置CheckBox的状态的话,由于复用问题会出问题,所以想出了用一个集合来保存它们状态的方法,不知道大家有没有其它更好的方法。

·OnCheckedChangedListener:向外暴露的接口,把点击的位置等參数都传到Activity中去。

·update():这种方法用来更新界面的,没有採用直接调notifyDataSetChanged方法是由于,假设数据的数量变化了那么listChecked的数量也要发生变化才行这样才干相应。所以写了这种方法。

再接着看看GalleryPopupWindow

/**
* Created by lzy on 2017/2/8.
*/
public class GalleryPopupWindow extends PopupWindow {
private static final String TAG = "lzy"; RecyclerView mRecyclerView; private Activity activity;
private GalleryPopupWindow.OnItemClickListener onItemClickListener;
private List<ImageBean> list;
private GalleryAdapter adapter; public GalleryPopupWindow(Activity context, List<ImageBean> list) {
super(context);
this.activity = context;
this.list = list;
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View contentView = inflater.inflate(R.layout.popu_gallery, null);
initView(contentView); int h = context.getWindowManager().getDefaultDisplay().getHeight();
int w = context.getWindowManager().getDefaultDisplay().getWidth();
this.setContentView(contentView);
this.setWidth(w);
this.setHeight(ImageSelecteActivity.dp2px(350, context));
this.setFocusable(false);
this.setOutsideTouchable(true);
this.update(); setBackgroundDrawable(new ColorDrawable(000000000));
} public void notifyDataChanged() {
adapter.notifyDataSetChanged();
} private void initView(View contentView) {
mRecyclerView = (RecyclerView) contentView.findViewById(R.id.rv_gallery);
mRecyclerView.setLayoutManager(new LinearLayoutManager(activity));
adapter = new GalleryAdapter(list, activity);
adapter.setOnItemClickListener(new GalleryAdapter.OnItemClickListener() {
@Override
public void onItemClick(String fileName) {
if (onItemClickListener != null) {
onItemClickListener.onItemClick(fileName);
dismiss();
}
}
});
mRecyclerView.setAdapter(adapter); } //暴露点击的接口
public interface OnItemClickListener {
/**
* @param keyValue
*/
void onItemClick(String keyValue);
} public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
}

这个PopupWindow的布局文件就是一个RecyclerView,所以这里面也没什么。也就是设置RecyclerView。然后向外暴露一个点击的接口,用于Activity接收是点击了哪个目录,所以接口參数也就是目录名,再看看这个PopupWindow的Adapter

/**
* Created by lzy on 2017/2/8.
*/
public class GalleryAdapter extends RecyclerView.Adapter<GalleryAdapter.NViewHolder> { private Context context;
private List<ImageBean> list;
private OnItemClickListener onItemClickListener;
//用于记录是选中的哪一个目录
private int selectedPos; public GalleryAdapter(List<ImageBean> list, Context context) {
this.list = list;
this.context = context;
} public interface OnItemClickListener {
void onItemClick(String fileName);
} public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
} @Override
public NViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new NViewHolder(LayoutInflater.from(context).inflate(R.layout.item_gallery, parent, false));
} @Override
public void onBindViewHolder(NViewHolder holder, final int position) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
selectedPos = position;
notifyDataSetChanged();
if (onItemClickListener != null) {
onItemClickListener.onItemClick(list.get(position).getFileName());
}
}
});
if (position == selectedPos) {
holder.ivCheck.setVisibility(View.VISIBLE);
} else {
holder.ivCheck.setVisibility(View.GONE);
}
holder.tvCount.setText(list.get(position).getCount() + "张");
holder.tvName.setText(list.get(position).getFileName());
Glide.with(context).load("file://" + list.get(position).getFirstPicPath()).into(holder.iv);
} @Override
public int getItemCount() {
return list.size();
} public class NViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.iv_itemGallery)
ImageView iv;
@BindView(R.id.tv_itemGallery_name)
TextView tvName;
@BindView(R.id.tv_itemGallery_count)
TextView tvCount;
@BindView(R.id.iv_itemGallery_check)
ImageView ivCheck; public NViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
} }

这里有个接口是把点击的文件名称传递给PopupWindow。然后再给Activity。selectedPos是用来记录选择的是哪一个目录。显示相应的CheckBox。

这里就几乎相同完毕了,感兴趣的能够下载Demo来看看。

再说一下,这里显示图片都是採用的Glide。使用也非常方便,我们获取的图片路径都是文件路径。假设要转化为Bitmap也能够直接调用Glide的方法就能够轻松实现,例如以下所看到的:

Glide.with(this).load("file://" + listSelectedPath.get(i)).asBitmap().into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
Log.i(TAG, "onResourceReady: " + resource);
}
});

当中找寻控件都没有使用findViewById,而是採用的ButterKnife。节约了大量的时间,顺便说说导入的方法

在app以下的build.gradle中加入以下:

apply plugin: 'com.neenbedankt.android-apt'
apt 'com.jakewharton:butterknife-compiler:8.1.0'
compile 'com.github.bumptech.glide:glide:3.5.2'

项目以下的build.gradle

 //加入apt插件
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'

加入插件

File->Setting->Plugins  搜索zelezny。例如以下所看到的

当须要使用的时候。直接在光标移动到布局文件,点击Alt+Insert。选择Generate ButterKnife Injections

就出现例如以下界面,能够自己主动生成了

源代码地址:http://download.csdn.net/detail/lylodyf/9768761

Android实现本地图片选择及预览缩放效果仿春雨医生的更多相关文章

  1. JavaScript实现本地图片上传预览功能(兼容IE、chrome、FF)

    需要解决的问题有:本地图片如何在上传前预览.编辑:最近发现这个功能很多是基于flash实现的,很多JavaScript实现的代码兼容性都很差,特别是在IE和firefox和chrome三个浏览器上不兼 ...

  2. 微信小程序图片选择,预览和删除

    这里均用的是小程序原生api 废话不多说直接上栗子: <view class="addImv"> <!--这个是已经选好的图片--> <view wx ...

  3. jquery实现本地图片上传预览和限流处理

    <html> <head> <meta http-equiv="Content-Type" content="text/html; char ...

  4. JS实现上传本地图片前先预览

    <style type="text/css"> #preview /*这个就是预览的DIV的ID*/ { filter:progid:DXImageTransform. ...

  5. HTML5实现图片选择并预览

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs& ...

  6. Html5选择图片并及时预览图片

    以往想要实现图片预览基本都是先传至服务器后等返回链接地址才能进行预览,使用Html5选择图片并及时预览图片的代码如下,使用起来更爽了. <!DOCTYPE html> <html l ...

  7. input type=file 选择图片并且实现预览效果的实例

    为大家带来一篇input type=file 选择图片并且实现预览效果的实例. 通过<input />标签,给它指定type类型为file,可提供文件上传: accept:可选择上传类型, ...

  8. vue使用readAsDataURL实现选择图片文件后预览

    vue实现选择图片文件后预览 利用h5的api可以实现选择文件并实现预览 readAsDataURL 方法会读取指定的 Blob 或 File 对象.读取操作完成的时候,readyState 会变成已 ...

  9. js实现图片上传预览及进度条

    原文js实现图片上传预览及进度条 最近在做图片上传的时候,由于产品设计的比较fashion,上网找了比较久还没有现成的,因此自己做了一个,实现的功能如下: 1:去除浏览器<input type= ...

随机推荐

  1. [转]Python UnicodeEncodeError: ‘ascii’ codec can’t encode characters in position 的解决办法

    UnicodeEncodeError: ‘ascii’ codec can’t encode characters in position 的解决办法 python在安装时,默认的编码是ascii,当 ...

  2. SSL 延迟与 Http、Https

    SSL延迟有多大? 1. 基本概念 ssl 协议由网景公司(Netscape)设计,由此网络链接从 http 逐步走向更为安全的 https 加密链接模式. HTTPs 链接和 HTTP 链接都建立在 ...

  3. Copying lists

    When you assign an object to a variable, Python copies the reference to the object. In this case a a ...

  4. SQL SERVER中求上月、本月和下月的第一天和最后一天

    1.上月的第一天 SELECT CONVERT(CHAR(10),DATEADD(month,-1,DATEADD(dd,-DAY(GETDATE())+1,GETDATE())),111) 2.上月 ...

  5. vuejs scope

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  6. 学以敩(xiao,效)为敎,以见为觉。醒悟、明白。

    学以敩(xiao,效)为敎,以见为觉.醒悟.明白 上半部分中间的爻是算筹,在古时被用来记数和计算:两边是手,既表示手把手传授,双手也表恭敬与专注:中间是一座房子,表示教学和学习的地方,这个地方不用豪华 ...

  7. tensorflow 1 - 起步

    使用图 (graph) 来表示计算任务. 在被称之为 会话 (Session) 的上下文 (context) 中执行图. 使用 tensor 表示数据. 通过 变量 (Variable) 维护状态. ...

  8. vue分页组件火狐中出现样式问题

    分页的操作到了火狐浏览器会样式 怎么解决? 其实就是将input的type属性变成了text,因为number属性会变成上下的小箭头

  9. 运行npm start vue.js项目 出现 npm ERR! missing script: start 错误

    npm ERR! missing script: start 错误 有可能缺少依赖包,运行nmp install安装依赖(一般都依赖很多包,过程有点慢),安装完后发现多一个 node_modules文 ...

  10. POJ 3539 Elevator(同余类BFS)

    题意 有一部电梯,最初停在1层. 电梯有4个按键,上升a,b,c层,回到一层. 求从一层出发.能到达1~h的哪些楼层. (h<=1018,a,b,c<=105) 题解 这种h能大的图论,一 ...