android自带下拉阻尼动画,android 有阻尼下拉刷新列表的实现方法

本文将会介绍有阻尼下拉刷新列表的实现,先来看看效果预览:

这是下拉状态:

3eed5afa9f308af55577f5004b28bc18.png

这是下拉松开手指后listView回滚到刷新状态时的样子:

47da18f0311d9ca069bc3a6aa2341abd.png

1. 如何调用

虽然效果图看起来样子不太好看,主要是因为那个蓝色的背景对不对,没关系,这只是一个背景而已,在了解了我们这个下拉刷新列表的实现之后,你就可以很轻松地修改这个背景,从而实现你想要的UI效果!话不多说,下面我们先来讲讲这个下拉刷新列表是如何使用的,这也是我们编写代码所要实现的目标。

final PullToRefreshListView eListView = (PullToRefreshListView) rootView.findViewById(R.id.profile_listView);

eListView.setOnLoadCallBack(new PullToRefreshListView.OnLoadCallBack() {

@Override

public int whereToLoad() {

return PullToRefreshListView.DEFAULT_WHERE_TO_LOAD;

}

@Override

public void onLoad() {

eListView.postDelayed(new Runnable() {

@Override

public void run() {

eListView.setLoadingFinish();

}

}, 5000);

}

@Override

public void cancelLoad() {

}

@Override

public Drawable refreshDrawable() {

return new ColorDrawable(Color.CYAN);

}

});

eListView.setAdapter(new BaseAdapter() {

@Override

public int getCount() {

return 30;

}

@Override

public Object getItem(int position) {

return null;

}

@Override

public long getItemId(int position) {

return 0;

}

@Override

public View getView(int position, View convertView, ViewGroup parent) {

TextView tv;

if (convertView == null) {

tv = new TextView(getActivity());

tv.setGravity(Gravity.CENTER_VERTICAL);

tv.setHeight(200);

tv.setBackgroundColor(Color.WHITE);

} else {

tv = (TextView) convertView;

}

tv.setText(position+"");

return tv;

}

});

在上述代码中,我们可以看到PullToRefreshListView的使用在adapter上跟ListView是一样的,这个当然,因为我们实现下拉刷新功能并不需要修改数据适配器。我们也看到,PullToRefreshListView的实例需要设置一个OnLoadCallBack回调,该回调需要实现4个方法,包括:

/**

* 下拉刷新的回调

*/

public interface OnLoadCallBack {

/**

* 下拉结束后将listView定位到哪个位置等待刷新完成

* @return listView的定位y坐标值,in dp

*/

int whereToLoad();

/**

* 下拉结束后进行刷新的回调

*/

void onLoad();

/**

* 取消刷新

*/

void cancelLoad();

/**

* 下拉刷新的背景

* @return 背景drawable

*/

Drawable refreshDrawable();

}

whereToLoad方法告知PullToRefreshListView对象下拉刷新时停留在哪个位置,具体点说,也就是上述第二章效果图中蓝色背景的高度。onLoad方法是下拉刷新的回调,调用者可以在这里实现刷新动作。cancelLoad方法是取消刷新动作的回调,调用者需要在这里将刷新动作取消。

根据上述方法,我们可以猜测,在onLoad方法中执行的应该是一个线程或者AsyncTask,而在cancelLoad方法中要做的就是将这个线程或者AsyncTask取消掉。最后还有一个refreshDrawable方法,这个方法是为修改listView的背景而提供给调用者的,调用者可以返回任意一个喜欢的背景Drawable。

知道如何调用以后,我们就要一步一步地实现这个PullToRefreshListView了。

2. 在dispatchDraw中重画子View实现下拉视觉

PullToRefreshListView实现的关键在于重画该listVIew的子View。重画ViewGroup的子View一般是在dispatchDraw方法中实现的。因此,我们的PullToRefreshListView继承自ListView类,重载其dispatchDraw方法。

@Override

protected void dispatchDraw(Canvas canvas) {

super.dispatchDraw(canvas);

if (distanceY > 0) {

if (refreshDrawable == null) {

refreshDrawable = onLoadCallBack.refreshDrawable();

}

if (refreshDrawable == null) {

canvas.drawColor(Color.GRAY);

} else {

int left = getPaddingLeft();

int top = getPaddingTop();

refreshDrawable.setBounds(left, top, getWidth()+left, getHeight()+top);

refreshDrawable.draw(canvas);

}

canvas.save();

canvas.translate(getPaddingLeft(), getPaddingTop() + distanceY);

for (int i=0;i

View child = getChildAt(i);

drawChild(canvas, child, getDrawingTime());

}

canvas.restore();

}

}

重画子View的关键在于这一句代码:

canvas.translate(getPaddingLeft(), getPaddingTop() + distanceY);

在重画子View之前,我们需要先将canvas向上移动distanceY距离。这是为什么呢?我们先来看看在canvas画子View的方法

drawChild方法的文档是怎么说的。

protected boolean drawChild (Canvas canvas, View child, long drawingTime)

Added in API level 1 Draw one child of this View Group. This method is responsible for getting the canvas in the right state. This includes clipping, translating so that the child's scrolled origin is at 0, 0, and applying any animation transformations.

Parameters canvas The canvas on which to draw the child child Who to draw drawingTime The time at which draw is occurring Returns True if an invalidate() was issued

我来翻译一下,drawChild方法可以画出这个View Group的一个子View。该方法需要使canvas处于一个正确的状态,该状态就

是通过对canvas进行clip裁剪,translate评议操作等以使得该子View位于canvas的(0,0)位置。

什么意思呢?简单来说就是,drawChild方法会将child view画在canvas的(0,0)位置,因此为了使得该child view位于

canvas的正确位置,我们需要在重画之前对canvas进行裁剪平移等操作。举个例子,有一个canvas和一个child view,本来

child view要画在(0,0)位置上,于是呈现在我们眼前的child view就是位于canvas的顶部,但是如果在画之前我们将

canvas向上移动100个像素单位,然后再将child view画在(0,0)位置上,那么呈现在我们眼前的child view的位置将会是

位于canvas的(0,100)位置上。

根据以上分析,我们可以知道,重画子View的原理就是:

当PullToRefreshListView已经滚动到顶部的时候,通过监控滑动手势来计算distanceY,从而确定要将canvas向上移动多少再重画子View,就可以实现PullToRefreshListView跟随滑动手势进行下拉的功能了。

3. 计算下拉距离

实现了重画以后,我们需要做的就是如何计算distanceY。我们的初步想法是,根据滑动的距离来计算,考虑到我们要实现阻尼效果,即随着滑动距离的变长,PullToRefreshListView的下拉距离会越来越短。在PullToRefreshListView实现中,我使用指数函数来实现这一阻尼效果,具体计算如下:

distanceY = ev.getY() - pullStartY;

distanceY = (float) (Math.exp(-ev.getY() / pullStartY / 40) * distanceY);

我们知道负指数是加速度随距离变小的单调递增函数,我使用手指滑动距离计算负指数作为PullToRefreshListView的滑动距离的参考标准,便可以实现有阻尼下拉效果。

4. 监控手势判断ListView是否进入下拉状态并更新distanceY

更进一步,我们要实现的就是对手势的监控,在PullToRefreshListView中,我们在onTouchEvent方法中进行处理。

@Override

public boolean onTouchEvent(MotionEvent ev) {

if (lastAction == -1 && ev.getActionMasked() == MotionEvent.ACTION_DOWN) {

// 按下的时候

lastAction = MotionEvent.ACTION_DOWN;

cancelAnimating();

L.d(TAG, "touch down");

} else if (lastAction == MotionEvent.ACTION_MOVE && ev.getActionMasked() == MotionEvent.ACTION_UP) {

// 放开手指,开始回滚

isPulling = false;

lastAction = -1;

startAnimating();

L.d(TAG, "touch up");

} else if (lastAction == MotionEvent.ACTION_DOWN) {

if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) {

// 在按下手指的基础上,开始滑动

if (isTop && !isPulling) {

// listView在顶部而且不处于下拉刷新状态,开始下拉

pullStartY = ev.getY();

lastAction = MotionEvent.ACTION_MOVE;

isPulling = true;

}

}

} else if (lastAction == MotionEvent.ACTION_MOVE) {

if (isTop) {

// 下拉

distanceY = ev.getY() - pullStartY;

L.d(TAG, distanceY + "");

if (distanceY > 0) {

distanceY = (float) (Math.exp(-ev.getY() / pullStartY / 40) * distanceY);

// 在下拉状态时取消系统对move动作的响应,完全由本类响应

ev.setAction(MotionEvent.ACTION_DOWN);

} else {

distanceY = 0;

// 在下拉过程中往上拉动该listView使得其回到顶部位置,则将该move动作交由系统进行响应

ev.setAction(MotionEvent.ACTION_MOVE);

}

} else {

// 在下拉过程中往上拉动listView使listView往下滚动到其没有滚动到顶部,则取消其下拉状态,回到手指按下的初始状态

lastAction = MotionEvent.ACTION_DOWN;

isPulling = false;

distanceY = 0;

}

}

return super.onTouchEvent(ev);

}

这一段代码相对有一点复杂,我们慢慢解析。首先,我们有一个lastAction变量来记录上一个手势是什么,有一个isPulling变量来记录当前PullToRefreshListView是否处于下拉状态,有一个isTop变量记录当前PullToRefreshListView是否已经滚动到顶部。

在onTouchEvent方法的重载实现中,一开始PullToRefreshListView没有接受任何手势,然后当用户按下手指出发ACTION_DOWN事件时,我记录下这个动作,然后当用户进行滑动时,如果此时PullToRefreshListView没有“滚动到顶部”,则不做任何处理,反之则将lastAction更新为ACTION_MOVE状态,更新isPulling变量,记录当前手指的位置作为计算下拉距离的起始位置,开始下拉刷新,然后在下拉的过程中计算PullToRefreshListView下拉的距离以重画子View。

在这个手势处理的实现中,当用户在下拉过程中突然将PullToRefreshListView往上拉,如果将PullToRefreshListView 拉到不处于“滚动到顶部的状态”时,则重置下拉状态,使得:

lastAction = MotionEvent.ACTION_DOWN;

于是PullToRefreshListView接下来的下滑手势响应权被交还给系统,知道用户又将PullToRefreshListView下拉到“滚动到顶部”状态,则又重新执行上述操作,使PullToRefreshListView进入下拉状态。

5. 如何判断ListView是否已经滚动到顶部

下一步,我们如何判断ListView是否处于“滚动到顶部”状态呢?这一问题我PullToRefreshListView的onScroll中解决。

setOnScrollListener(new OnScrollListener() {

@Override

public void onScrollStateChanged(AbsListView view, int scrollState) {

}

@Override

public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

// 没有子view的时候(没有数据,或者被拉到看不到子view),意味着该listView滚动到顶部

if (getChildCount() == 0) {

isTop = true;

return;

}

if (firstVisibleItem == 0) {

View firstView = getChildAt(0);

if (firstView.getTop() + distanceY >= 0) {

// 第一个view可见且其相对parent(该listView)的顶部距离大于等于0,意味着该listView也是滚动到顶部

isTop = true;

return;

}

}

isTop = false;

}

});

为PullToRefreshListView设置一个OnScrollListener回调,并在其onScroll方法中监控其滚动位置,具体看注释也已经一目了然,我就不多解释了。

6. 下拉后的回滚动画

最后,当下拉结束松开手指时,我们需要为PullToRefreshListView执行一个回滚的动画,我们在onTouchEvent方法中看到:

// ......

else if (lastAction == MotionEvent.ACTION_MOVE && ev.getActionMasked() == MotionEvent.ACTION_UP) {

// 放开手指,开始回滚

isPulling = false;

lastAction = -1;

startAnimating();

L.d(TAG, "touch up");

}

// ......

startAnimating方法的实现如下:

/**

* 下拉结束时进行回滚动画并执行刷新动作

*/

private void startAnimating() {

int whereToLoad = dp2px(onLoadCallBack.whereToLoad());

final boolean toLoad;

if (distanceY <= whereToLoad) {

pullCancelAnimator = ValueAnimator.ofFloat(distanceY, 0);

toLoad = false;

} else {

pullCancelAnimator = ValueAnimator.ofFloat(distanceY, whereToLoad);

toLoad = true;

}

pullCancelAnimator.setDuration((long) (DEFAULT_BASE_ANIMATING_TIME_PER_100DP*px2dp(distanceY)/100));

pullCancelAnimator.setInterpolator(new AccelerateDecelerateInterpolator());

pullCancelAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

distanceY = (float) animation.getAnimatedValue();

ViewCompat.postInvalidateOnAnimation(PullToRefreshListView.this);

}

});

pullCancelAnimator.addListener(new Animator.AnimatorListener() {

@Override

public void onAnimationStart(Animator animation) {

}

@Override

public void onAnimationEnd(Animator animation) {

post(new Runnable() {

@Override

public void run() {

pullCancelAnimator = null;

if (toLoad) {

onLoadCallBack.onLoad();

}

}

});

}

@Override

public void onAnimationCancel(Animator animation) {

post(new Runnable() {

@Override

public void run() {

pullCancelAnimator = null;

if (toLoad) {

onLoadCallBack.cancelLoad();

}

}

});

}

@Override

public void onAnimationRepeat(Animator animation) {

}

});

pullCancelAnimator.start();

}

我使用ValueAnimator来实现这一回滚动画,其中为ValueAnimator设置的回调中,在动画更新和动画结束以及动画取消中分别调用了OnLoadCallBack的3歌回调方法,从而实现PullToRefreshListView的下拉刷新动作。我们可以看到,onLoad方法是在UI线程执行的,因此如果在onLoad方法中执行耗时操作的话,需要在后台线程中操作,这与我们前面的解析是对应的。

7. 改进和问题

(1) 我们可以将onLoad回调修改成一个返回一个异步任务对象的方法,然后PullToRefreshListView在下拉结束后执行这个异步任务,因此我们就可以不需要cancelLoading回调了,直接就可以在PullToRefreshListView内部进行取消操作,这样做可以增强封装性,但相对目前的做法自由度就没有那么高了。

(2) 回滚动画应该也可以进行优化,具体怎么优化我也不清楚。。。各位朋友有好的想法可以在评论区提议一下,谢谢~

(3) 下拉的时候对多点触碰的响应并不完美,虽然也可以接受,但是做不到像qq客户端的聊天列表那样。

8. 源码

至此,我已经解析了如何实现一个下拉刷新列表,PullToRefreshListView的源码如下。

import android.animation.Animator;

import android.animation.ValueAnimator;

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.drawable.Drawable;

import android.support.v4.view.ViewCompat;

import android.util.AttributeSet;

import android.view.MotionEvent;

import android.view.View;

import android.view.animation.AccelerateDecelerateInterpolator;

import android.widget.AbsListView;

import android.widget.ListView;

import com.ivan.healthcare.healthcare_android.log.L;

/**

* 支持下拉刷新的的listView

* Created by Ivan on 16/2/14.

*/

public class PullToRefreshListView extends ListView {

private final String TAG = "PullToRefreshListView";

private final int DEFAULT_BASE_ANIMATING_TIME_PER_100DP = 150;

public static final int DEFAULT_WHERE_TO_LOAD = 80;

private int lastAction = -1;

private float pullStartY = -1;

private boolean isTop = true;

private float distanceY = 0;

private boolean isPulling = false;

private ValueAnimator pullCancelAnimator;

private Context context;

private Drawable refreshDrawable;

private OnLoadCallBack onLoadCallBack = new OnLoadCallBack() {

@Override

public int whereToLoad() {

return DEFAULT_WHERE_TO_LOAD;

}

@Override

public void onLoad() {

}

@Override

public void cancelLoad() {

}

@Override

public Drawable refreshDrawable() {

return null;

}

};

public PullToRefreshListView(Context context) {

super(context);

initView(context);

}

public PullToRefreshListView(Context context, AttributeSet attrs) {

super(context, attrs);

initView(context);

}

private void initView(Context context) {

this.context = context;

setOnScrollListener(new OnScrollListener() {

@Override

public void onScrollStateChanged(AbsListView view, int scrollState) {

}

@Override

public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

// 没有子view的时候(没有数据,或者被拉到看不到子view),意味着该listView滚动到顶部

if (getChildCount() == 0) {

isTop = true;

return;

}

if (firstVisibleItem == 0) {

View firstView = getChildAt(0);

if (firstView.getTop() + distanceY >= 0) {

// 第一个view可见且其相对parent(该listView)的顶部距离大于等于0,意味着该listView也是滚动到顶部

isTop = true;

return;

}

}

isTop = false;

}

});

}

@Override

public boolean onTouchEvent(MotionEvent ev) {

if (lastAction == -1 && ev.getActionMasked() == MotionEvent.ACTION_DOWN) {

// 按下的时候

lastAction = MotionEvent.ACTION_DOWN;

cancelAnimating();

L.d(TAG, "touch down");

} else if (lastAction == MotionEvent.ACTION_MOVE && ev.getActionMasked() == MotionEvent.ACTION_UP) {

// 放开手指,开始回滚

isPulling = false;

lastAction = -1;

startAnimating();

L.d(TAG, "touch up");

} else if (lastAction == MotionEvent.ACTION_DOWN) {

if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) {

// 在按下手指的基础上,开始滑动

if (isTop && !isPulling) {

// listView在顶部而且不处于下拉刷新状态,开始下拉

pullStartY = ev.getY();

lastAction = MotionEvent.ACTION_MOVE;

isPulling = true;

}

}

} else if (lastAction == MotionEvent.ACTION_MOVE) {

if (isTop) {

// 下拉

distanceY = ev.getY() - pullStartY;

L.d(TAG, distanceY + "");

if (distanceY > 0) {

distanceY = (float) (Math.exp(-ev.getY() / pullStartY / 40) * distanceY);

// 在下拉状态时取消系统对move动作的响应,完全由本类响应

ev.setAction(MotionEvent.ACTION_DOWN);

} else {

distanceY = 0;

// 在下拉过程中往上拉动该listView使得其回到顶部位置,则将该move动作交由系统进行响应

ev.setAction(MotionEvent.ACTION_MOVE);

}

} else {

// 在下拉过程中往上拉动listView使listView往下滚动到其没有滚动到顶部,则取消其下拉状态,回到手指按下的初始状态

lastAction = MotionEvent.ACTION_DOWN;

isPulling = false;

distanceY = 0;

}

}

return super.onTouchEvent(ev);

}

@Override

protected void dispatchDraw(Canvas canvas) {

super.dispatchDraw(canvas);

if (distanceY > 0) {

if (refreshDrawable == null) {

refreshDrawable = onLoadCallBack.refreshDrawable();

}

if (refreshDrawable == null) {

canvas.drawColor(Color.GRAY);

} else {

int left = getPaddingLeft();

int top = getPaddingTop();

refreshDrawable.setBounds(left, top, getWidth()+left, getHeight()+top);

refreshDrawable.draw(canvas);

}

canvas.save();

canvas.translate(getPaddingLeft(), getPaddingTop() + distanceY);

for (int i=0;i

View child = getChildAt(i);

drawChild(canvas, child, getDrawingTime());

}

canvas.restore();

}

}

/**

* 下拉结束时进行回滚动画并执行刷新动作

*/

private void startAnimating() {

int whereToLoad = dp2px(onLoadCallBack.whereToLoad());

final boolean toLoad;

if (distanceY <= whereToLoad) {

pullCancelAnimator = ValueAnimator.ofFloat(distanceY, 0);

toLoad = false;

} else {

pullCancelAnimator = ValueAnimator.ofFloat(distanceY, whereToLoad);

toLoad = true;

}

pullCancelAnimator.setDuration((long) (DEFAULT_BASE_ANIMATING_TIME_PER_100DP*px2dp(distanceY)/100));

pullCancelAnimator.setInterpolator(new AccelerateDecelerateInterpolator());

pullCancelAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

distanceY = (float) animation.getAnimatedValue();

ViewCompat.postInvalidateOnAnimation(PullToRefreshListView.this);

}

});

pullCancelAnimator.addListener(new Animator.AnimatorListener() {

@Override

public void onAnimationStart(Animator animation) {

}

@Override

public void onAnimationEnd(Animator animation) {

post(new Runnable() {

@Override

public void run() {

pullCancelAnimator = null;

if (toLoad) {

onLoadCallBack.onLoad();

}

}

});

}

@Override

public void onAnimationCancel(Animator animation) {

post(new Runnable() {

@Override

public void run() {

pullCancelAnimator = null;

if (toLoad) {

onLoadCallBack.cancelLoad();

}

}

});

}

@Override

public void onAnimationRepeat(Animator animation) {

}

});

pullCancelAnimator.start();

}

private void cancelAnimating() {

if (pullCancelAnimator != null) {

pullCancelAnimator.cancel();

}

}

private float px2dp(float pxvalue) {

return (pxvalue - 0.5f) /context.getResources().getDisplayMetrics().density;

}

private int dp2px(float dpvalue) {

return (int) (dpvalue * context.getResources().getDisplayMetrics().density + 0.5f);

}

/**

* 下拉刷新的回调

*/

public interface OnLoadCallBack {

/**

* 下拉结束后将listView定位到哪个位置等待刷新完成

* @return listView的定位y坐标值,in dp

*/

int whereToLoad();

/**

* 下拉结束后进行刷新的回调

*/

void onLoad();

/**

* 取消刷新

*/

void cancelLoad();

/**

* 下拉刷新的背景

* @return 背景drawable

*/

Drawable refreshDrawable();

}

/**

* 设置下拉刷新回调

* @param cb 回调

*/

public void setOnLoadCallBack(OnLoadCallBack cb) {

this.onLoadCallBack = cb;

}

/**

* 刷新动作结束后调用该方法结束刷新,使得listView回滚到顶部

*/

public void setLoadingFinish() {

startAnimating();

}

}

以上这篇android 有阻尼下拉刷新列表的实现方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/533307.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

android viewpager画廊,Android使用ViewPager实现画廊效果

按照国际惯例&#xff0c;先上效果图其实这跟普通的ViewPager原理都一样&#xff0c;需要改变的地方就是&#xff1a;1.增加滑进和滑出的动画效果2.缩小ViewPager的大小&#xff0c;给屏幕上留出上一张和下一张视图的空间布局文件&#xff1a;xmlns:android"http://schema…

excel 区间人数柱状图_Excel中,区间统计的3种技巧都不掌握,那就真的OUt了!

点击上方"Excel函数公式"免费订阅 Excel的最大功能在于数据的分析与处理&#xff0c;在数据分析和处理中&#xff0c;区间统计是非常广泛的&#xff0c;各位亲是怎么操作的呢&#xff1f;如果还不掌握&#xff0c;且看小编给大家带来的“区间统计”的3种应用技巧。一…

nova8pro能升级鸿蒙吗,华为将有48款产品可以升级到鸿蒙 2.0系统

网站Huawei Central最近报道称&#xff0c;将有48款产品可以升级到鸿蒙 2.0系统&#xff0c;包括华为及其子品牌Honor的智能手机&#xff0c;平板电脑和智能手表。 Huawei Central名单中有3款未发布的手机Huawei Nova 8和Nova 8 Pro&#xff0c;以及Honor V40。 它们将在推出时…

patran如何看屈曲因子_校准证书中的修正值、修正因子,你真的会用吗?

一些仪器设备校准回来会产生修正值/修正因子&#xff0c;然而很多实验室小伙伴们不懂得如何正确使用这些修正值/修正因子&#xff1f;为帮助广大实验室能规范正确地使用修正值/修正因子&#xff0c;小析姐 特为大家推送这篇文章~【概念】修正值&#xff1a;为修正某一测量器具的…

android 生成debug.keystore,android sdk 如何重新生成debug.keystore

1)首先你要确定你安装的JDK位置&#xff0c;Windows->Preferences->Java->Installed JREs,你可以看到是Jre的location,再在dos cmd模式下查看你当前系统的path是否已经包含了。如果没有包含添加到当前环境参数中。因为我们要用到的keytool命令在这个目录下呀。2)接下来…

已知a类被打包在packagea_2021考研干货:199管理类联考综合逻辑归纳习题(1)

199管理类联考综合中的逻辑&#xff0c;所占分值为60分。因此&#xff0c;备考2021考研199管综的考生们&#xff0c;需要在内容上面多下功夫复习。题目&#xff1a;小张夫妇想买套房子&#xff0c;经他一番挑选&#xff0c;目标锁定某座楼的3套房。已知&#xff1a;这三套房子中…

凯立德手机导航(家园版) v5.3 for android,凯立德手机导航(家园版)android平台

感谢您阅读凯立德手机导航产品下载安装教程&#xff0c;请根据以下步骤进行操作。下载安装过程完成后&#xff0c;您将体验到更为专业的凯立德导航服务。安装前请认真阅读以下文字&#xff1a;1、为了减少导航产品所占容量&#xff0c;本导航产品分主程序和地图数据两部分。下载…

clocks_per_sec 时间不正确_你该拥有的不只是护肤品,还有正确护肤时间表

同样是护肤&#xff0c;为什么你的效果始终不如意&#xff1f;其实&#xff0c;不同的时间段&#xff0c;皮肤各司其职&#xff0c;都有着不同的“任务”和“状态”。快跟芭姐一起了解一下这份《皮肤时间表》&#xff0c;看看如何让护肤效果事半功倍吧&#xff01;清洁是唤醒肌…

HTML下拉菜单怎么做成横向,css导航条横向带下拉菜单

cssdiv导航下拉二级菜单竖排效果如何改为横排&#xff1f;&#xff0c;在“下一站”有三个二级竖排菜单&#xff0c;如何能变为横排&#xff1f;困扰了我一天了&#xff0c;让二级菜单变成一行&#xff0c;只需要在竖排的效果上&#xff0c;让二级菜单都浮动起来&#xff0c;这…

html5折叠卡片,基于HTML5折叠卡片式下拉菜单代码

基于HTML5折叠卡片式下拉菜单代码。这是一款基于jQueryCSS3HTML5实现的下拉列表框特效代码。效果图如下&#xff1a;实现的代码。hmtl代码&#xff1a;爱编程爱编程 jQuery特效 CSS3特效 HTML5特效 音效下载 flash动画js代码&#xff1a;(function ($) {var cards $(.card-dro…

fastexcel读取excel追加写入sheet页_python笔记52:python操作excel

主要内容&#xff1a;小目标&#xff1a;掌握excel模块主要内容&#xff1a;excel相关模块&#xff0c;openpyxl安装使用如果看完这篇文章&#xff0c;你还是弄不明excel相关操作&#xff1b; 你来找我&#xff0c;我保证不打你&#xff0c;我给你发100的大红包。1. excel相关操…

HTML音乐播放没声音,网页没有声音但系统显示有声音怎么回事?如何解决?

网友提问&#xff1a;为什么网页没有声音&#xff0c;除了迅雷高清在线影院的视频有声音和本已经下载的歌或视频有声音外&#xff0c;其他网页都没有声音&#xff01;就是网页没声音&#xff0c;其他一切正常&#xff01;网页没有声音但系统显示有声音&#xff1b;网页在线视频…

cesium 经纬度绘制点_炫酷大屏地图自定义绘制(一)

现在数据中台的概念炒的火热&#xff0c;那在收集到数据后就要想办法去设计大屏&#xff0c;可视化展现。往往大屏都会涉及到地理位置的显示。对于常见的省市区&#xff0c;网上都已经提供了地理json数据&#xff0c;那对于需要定制化的我们要怎么处理呢&#xff1f;首先我们还…

html瞄点四大名著有图片,四大名著手抄报图片图和文字资料

四大名著之【三国演义】罗贯中(1330年一1400年之间)&#xff0c;名本&#xff0c;号湖海散人&#xff0c;明代通俗小说家。他的籍贯一说是太原(今山西)&#xff0c;一说是钱塘(今浙江杭州)&#xff0c;不可确考。据传说&#xff0c;罗贯中曾充任过元末农民起义军张士诚的幕客&a…

怎样查询2021高考模拟成绩,2021年高三一模二模三模哪个成绩更接近高考成绩,看看网友是怎么评论...

2021年高三一模二模三模哪个成绩更接近高考成绩虽然大多数人认为一模的成绩最接近高考&#xff0c;基本定型了&#xff0c;但高考变幻莫测&#xff0c;成绩很有可能发生变化&#xff0c;成绩升降都是很难说的。高三一模之后成绩也没有定型&#xff0c;还有最后逆转的机会。高考…

js遍历json数组给html td赋值,JS实现给json数组动态赋值的方法示例

关注微信公众号JS实现给json数组动态赋值的方法示例转载 更新时间&#xff1a;2017年07月04日 10:19:00 作者&#xff1a;小魏的马仔这篇文章主要介绍了JS实现给json数组动态赋值的方法,结合实例形式分析了javascript针对json数组的遍历、赋值等常用操作技巧,需要的朋友可以…

计算机科学与技术专业实习招聘,中科院研究生院招聘GIS或计算机专业实习生

中科院研究生院招聘GIS或计算机专业实习生由于项目需要&#xff0c;中科院研究生院特招聘GIS或计算机方向实习生&#xff0c;具体要求如下&#xff1a;项目名称&#xff1a;油气田WebGIS系统招聘人数&#xff1a;1人(目前已有1人)主要工作是根据油气田生产需要,实现WebGIS支持下…

html div如何列对其,CSS:自适应N列布局如何解决两端对齐

关于每行N列的这种布局&#xff0c;存在一个两端对齐的问题&#xff0c;因为每一列都会存在一个margin-left或者margin-right&#xff0c;导致最后一个超出父元素的边界。通过一番努力&#xff0c;终于解决了这个遗留很久的问题&#xff0c;废话不多说&#xff0c;先看做完之后…

v380智能快配连接不上怎么办_Win7系统电脑设置连接远程桌面的操作方法

Win7系统电脑远程桌面无法连接怎么办&#xff1f;Win7怎么设置连接远程桌面&#xff1f;请看下文具体操作步骤。一般情况下&#xff0c;对Win7的远程连接只需要5步即可完成远程连接的设置&#xff1a;1)查询并记录远程计算机的IP&#xff0c;开始——运行——输入cmd&#xff0…

计算机专业买win,新买的电脑是win10系统,有的人却费尽心思重装成win7,为什么呢...

简单地说&#xff0c;现在的新电脑几乎都是最新的windows系统&#xff0c;而厂商通常预装的是windows10家庭版&#xff0c;虽说没有多强的功能&#xff0c;但也能够满足我们日常使用的需求。重要的是预装的win10系统是正版的&#xff01;但不难发现&#xff0c;即便是正版的win…