我想像Samsung Android Phones调用功能一样在ListView中实现Swipe
我有一个列表,如下图所示:
现在,当我从左侧滑动一定距离(即 25% 的距离)向右侧滑动时,它只是改变了背景,就像三星设备中的调用功能或 SwipeListView 一样:
为此需要解决方案。
最佳答案
试试这段代码:
<ListView
android:id="@+id/listView1"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:gravity="left"
android:text="ABC"
android:textSize="22sp" />
<LinearLayout
android:id="@+id/delete_lay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#55ff0000"
android:visibility="gone" >
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"
android:src="@drawable/ic_menu_delete"
android:visibility="visible" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"
android:gravity="left"
android:text="Deleting..."
android:textColor="#ff0000"
android:textSize="22sp"
android:textStyle="bold" />
</LinearLayout>
import java.util.ArrayList;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.LayoutParams;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import de.timroes.swipetodismiss.SwipeDismissList;
import de.timroes.swipetodismiss.SwipeDismissList.SwipeDirection;
import de.timroes.swipetodismiss.SwipeDismissList.UndoMode;
import de.timroes.swipetodismiss.SwipeDismissList.Undoable;
public class MainActivity extends Activity {
ArrayList<String> listData;
ListView listView;
ArrayAdapter<String> adapter;
SwipeListAdapter listAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.listView1);
listData = new ArrayList<String>();
listData.add("item 1");
listData.add("item 2");
listData.add("item 3");
listData.add("item 4");
listData.add("item 5");
listData.add("item 6");
listData.add("item 7");
listData.add("item 8");
listData.add("item 9");
listData.add("item 10");
listData.add("item 11");
listData.add("item 12");
listData.add("item 13");
listData.add("item 14");
listData.add("item 15");
listData.add("item 16");
listData.add("item 17");
listAdapter = new SwipeListAdapter(MainActivity.this);
listView.setAdapter(listAdapter);
listAdapter.notifyDataSetChanged();
SwipeDismissList.OnDismissCallback callback = new SwipeDismissList.OnDismissCallback() {
@Override
public Undoable onDismiss(AbsListView listView, int position) {
View view = (View) listView.getChildAt(0);
view.animate().alpha(1).setDuration(200).translationX(10);
listAdapter.remove(position);
return null;
}
};
UndoMode mode = SwipeDismissList.UndoMode.SINGLE_UNDO;
SwipeDismissList swipeList = new SwipeDismissList(listView, callback,
mode);
swipeList.setSwipeDirection(SwipeDirection.END);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
class SwipeListAdapter extends BaseAdapter {
Context mContext;
public SwipeListAdapter(Context context) {
this.mContext = context;
}
@Override
public int getCount() {
return listData.size();
}
@Override
public Object getItem(int position) {
return listData.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
private void remove(int pos) {
listData.remove(pos);
notifyDataSetChanged();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
try {
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(
R.layout.raw, null);
}
TextView textView = (TextView) convertView
.findViewById(R.id.name);
textView.setText(listData.get(position));
RelativeLayout layout = (RelativeLayout) convertView
.findViewById(R.id.parentLayout);
LayoutParams params = new LayoutParams(
LayoutParams.MATCH_PARENT, 50);
layout.setLayoutParams(params);
} catch (Exception e) {
e.printStackTrace();
}
return convertView;
}
}
}
import static com.nineoldandroids.view.ViewHelper.setAlpha;
import static com.nineoldandroids.view.ViewHelper.setTranslationX;
import static com.nineoldandroids.view.ViewPropertyAnimator.animate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.nineoldandroids.animation.Animator;
import com.nineoldandroids.animation.AnimatorListenerAdapter;
import com.nineoldandroids.animation.ValueAnimator;
public final class SwipeDismissList implements View.OnTouchListener {
// Cached ViewConfiguration and system-wide constant values
private int mSlop;
private int mMinFlingVelocity;
private int mMaxFlingVelocity;
private long mAnimationTime;
// Fixed properties
private AbsListView mListView;
private OnDismissCallback mCallback;
private int mViewWidth = 1; // 1 and not 0 to prevent dividing by zero
// Transient properties
private SortedSet<PendingDismissData> mPendingDismisses = new TreeSet<PendingDismissData>();
private int mDismissAnimationRefCount = 0;
private float mDownX;
private boolean mSwiping;
private VelocityTracker mVelocityTracker;
private int mDownPosition;
private View mDownView;
private boolean mPaused;
private float mDensity;
private boolean mSwipeDisabled;
private UndoMode mMode;
private List<Undoable> mUndoActions;
private Handler mHandler;
private PopupWindow mUndoPopup;
private TextView mUndoText;
private Button mUndoButton;
private SwipeDirection mSwipeDirection = SwipeDirection.BOTH;
private int mAutoHideDelay = 5000;
private String mDeleteString = "Item deleted";
private String mDeleteMultipleString = "%d items deleted";
private boolean mTouchBeforeAutoHide = true;
private int mDelayedMsgId;
View frontView;
View backView;
RelativeLayout layout ;
public enum UndoMode {
SINGLE_UNDO,
MULTI_UNDO,
COLLAPSED_UNDO
};
public enum SwipeDirection {
BOTH,
START,
END
}
public interface OnDismissCallback {
Undoable onDismiss(AbsListView listView, int position);
}
public abstract static class Undoable {
public String getTitle() {
return null;
}
public abstract void undo();
public void discard() { }
}
public SwipeDismissList(AbsListView listView, OnDismissCallback callback) {
this(listView, callback, UndoMode.SINGLE_UNDO);
}
public SwipeDismissList(AbsListView listView, OnDismissCallback callback, UndoMode mode) {
if(listView == null) {
throw new IllegalArgumentException("listview must not be null.");
}
mHandler = new HideUndoPopupHandler();
mListView = listView;
mCallback = callback;
mMode = mode;
ViewConfiguration vc = ViewConfiguration.get(listView.getContext());
mSlop = vc.getScaledTouchSlop();
mMinFlingVelocity = vc.getScaledMinimumFlingVelocity();
mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();
mAnimationTime = listView.getContext().getResources().getInteger(
android.R.integer.config_shortAnimTime);
mDensity = mListView.getResources().getDisplayMetrics().density;
// -- Load undo popup --
LayoutInflater inflater = (LayoutInflater) mListView.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflater.inflate(R.layout.undo_popup, null);
mUndoButton = (Button)v.findViewById(R.id.undo);
mUndoButton.setOnClickListener(new UndoHandler());
mUndoButton.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
// If user tabs "undo" button, reset delay time to remove popup
mDelayedMsgId++;
return false;
}
});
mUndoText = (TextView)v.findViewById(R.id.text);
mUndoPopup = new PopupWindow(v);
mUndoPopup.setAnimationStyle(R.style.fade_animation);
// Get scren width in dp and set width respectively
int xdensity = (int)(mListView.getContext().getResources().getDisplayMetrics().widthPixels / mDensity);
if(xdensity < 300) {
mUndoPopup.setWidth((int)(mDensity * 280));
} else if(xdensity < 350) {
mUndoPopup.setWidth((int)(mDensity * 300));
} else if(xdensity < 500) {
mUndoPopup.setWidth((int)(mDensity * 330));
} else {
mUndoPopup.setWidth((int)(mDensity * 450));
}
mUndoPopup.setHeight((int)(mDensity * 56));
// -- END Load undo popu --
listView.setOnTouchListener(this);
listView.setOnScrollListener(this.makeScrollListener());
switch(mode) {
case SINGLE_UNDO:
mUndoActions = new ArrayList<Undoable>(1);
break;
default:
mUndoActions = new ArrayList<Undoable>(10);
break;
}
}
private void setEnabled(boolean enabled) {
mPaused = !enabled;
}
public void setAutoHideDelay(int delay) {
mAutoHideDelay = delay;
}
public void setSwipeDirection(SwipeDirection direction) {
mSwipeDirection = direction;
}
public void setUndoString(String msg) {
mDeleteString = msg;
}
public void setUndoMultipleString(String msg) {
mDeleteMultipleString = msg;
}
public void setRequireTouchBeforeDismiss(boolean require) {
mTouchBeforeAutoHide = require;
}
public void discardUndo() {
for(Undoable undoable : mUndoActions) {
undoable.discard();
}
mUndoActions.clear();
mUndoPopup.dismiss();
}
private AbsListView.OnScrollListener makeScrollListener() {
return new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView absListView, int scrollState) {
setEnabled(scrollState != AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
}
@Override
public void onScroll(AbsListView absListView, int i, int i1, int i2) {
}
};
}
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (this.mSwipeDisabled) {
return false;
}
if (mViewWidth < 2) {
mViewWidth = mListView.getWidth();
}
switch (motionEvent.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
if (mPaused) {
return false;
}
// TODO: ensure this is a finger, and set a flag
// Find the child view that was touched (perform a hit test)
Rect rect = new Rect();
int childCount = mListView.getChildCount();
int[] listViewCoords = new int[2];
mListView.getLocationOnScreen(listViewCoords);
int x = (int) motionEvent.getRawX() - listViewCoords[0];
int y = (int) motionEvent.getRawY() - listViewCoords[1];
View child;
for (int i = 0; i < childCount; i++) {
child = mListView.getChildAt(i);
child.getHitRect(rect);
if (rect.contains(x, y)) {
mDownView = child;
break;
}
}
if (mDownView != null) {
mDownX = motionEvent.getRawX();
mDownPosition = mListView.getPositionForView(mDownView);
mVelocityTracker = VelocityTracker.obtain();
mVelocityTracker.addMovement(motionEvent);
}
view.onTouchEvent(motionEvent);
return true;
}
case MotionEvent.ACTION_UP: {
if (mVelocityTracker == null) {
break;
}
float deltaX = motionEvent.getRawX() - mDownX;
mVelocityTracker.addMovement(motionEvent);
mVelocityTracker.computeCurrentVelocity(1000);
float velocityX = Math.abs(mVelocityTracker.getXVelocity());
float velocityY = Math.abs(mVelocityTracker.getYVelocity());
boolean dismiss = false;
boolean dismissRight = false;
if (Math.abs(deltaX) > mViewWidth / 2 && mSwiping) {
dismiss = true;
dismissRight = deltaX > 0;
} else if (mMinFlingVelocity <= velocityX && velocityX <= mMaxFlingVelocity
&& velocityY < velocityX && mSwiping && isDirectionValid(mVelocityTracker.getXVelocity())
&& deltaX >= mViewWidth * 0.2f) {
dismiss = true;
dismissRight = mVelocityTracker.getXVelocity() > 0;
}
if (dismiss) {
// dismiss
final View downView = frontView; // mDownView gets null'd before animation ends
final int downPosition = mDownPosition;
++mDismissAnimationRefCount;
animate(frontView)
.translationX(dismissRight ? mViewWidth : -mViewWidth)
.alpha(0)
.setDuration(mAnimationTime)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
performDismiss(downView, downPosition);
}
});
} else {
// cancel
animate(frontView)
.translationX(0)
.alpha(1)
.setDuration(mAnimationTime)
.setListener(null);
}
mVelocityTracker = null;
mDownX = 0;
mDownView = null;
mDownPosition = ListView.INVALID_POSITION;
mSwiping = false;
if(backView != null) {
backView.setVisibility(View.GONE);
frontView.setVisibility(View.VISIBLE);
setTranslationX(frontView, 0);
layout = null;
backView = null;
frontView = null;
}
break;
}
case MotionEvent.ACTION_MOVE: {
if(mTouchBeforeAutoHide && mUndoPopup.isShowing()) {
// Send a delayed message to hide popup
mHandler.sendMessageDelayed(mHandler.obtainMessage(mDelayedMsgId),
mAutoHideDelay);
}
if (mVelocityTracker == null || mPaused) {
break;
}
mVelocityTracker.addMovement(motionEvent);
float deltaX = motionEvent.getRawX() - mDownX;
// Only start swipe in correct direction
if(isDirectionValid(deltaX)) {
if (Math.abs(deltaX) > mSlop) {
mSwiping = true;
mListView.requestDisallowInterceptTouchEvent(true);
// Cancel ListView's touch (un-highlighting the item)
MotionEvent cancelEvent = MotionEvent.obtain(motionEvent);
cancelEvent.setAction(MotionEvent.ACTION_CANCEL
| (motionEvent.getActionIndex()
<< MotionEvent.ACTION_POINTER_INDEX_SHIFT));
mListView.onTouchEvent(cancelEvent);
}
} else {
mDownX = motionEvent.getRawX();
deltaX = 0;
}
if(layout == null) {
layout = (RelativeLayout) mDownView;
frontView = layout.getChildAt(0);
backView = layout.getChildAt(1);
}
if(deltaX > 50) {
backView.setVisibility(View.VISIBLE);
}
if (mSwiping) {
setTranslationX(frontView, deltaX);
setAlpha(frontView, Math.max(0f, Math.min(1f,
1f - 2f * Math.abs(deltaX) / mViewWidth)));
return true;
}
break;
}
}
return false;
}
private boolean isDirectionValid(float deltaX) {
int rtlSign = 1;
// On API level 17 and above, check if we are in a Right-To-Left layout
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
if(mListView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
rtlSign = -1;
}
}
// Check if swipe has been done in the corret direction
switch(mSwipeDirection) {
default:
case BOTH:
return true;
case START:
return rtlSign * deltaX < 0;
case END:
return rtlSign * deltaX > 0;
}
}
class PendingDismissData implements Comparable<PendingDismissData> {
public int position;
public View view;
public PendingDismissData(int position, View view) {
this.position = position;
this.view = view;
}
@Override
public int compareTo(PendingDismissData other) {
// Sort by descending position
return other.position - position;
}
}
private void performDismiss(final View dismissView, final int dismissPosition) {
// Animate the dismissed list item to zero-height and fire the dismiss callback when
// all dismissed list item animations have completed. This triggers layout on each animation
// frame; in the future we may want to do something smarter and more performant.
final ViewGroup.LayoutParams lp = dismissView.getLayoutParams();
final int originalHeight = dismissView.getHeight();
ValueAnimator animator = ValueAnimator.ofInt(originalHeight, 1).setDuration(mAnimationTime);
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
--mDismissAnimationRefCount;
if (mDismissAnimationRefCount == 0) {
// No active animations, process all pending dismisses.
for(PendingDismissData dismiss : mPendingDismisses) {
if(mMode == UndoMode.SINGLE_UNDO) {
for(Undoable undoable : mUndoActions) {
undoable.discard();
}
mUndoActions.clear();
}
Undoable undoable = mCallback.onDismiss(mListView, dismiss.position);
if(undoable != null) {
mUndoActions.add(undoable);
}
mDelayedMsgId++;
}
if(!mUndoActions.isEmpty()) {
changePopupText();
changeButtonLabel();
// Show undo popup
mUndoPopup.showAtLocation(mListView,
Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM,
0, (int)(mDensity * 15));
// Queue the dismiss only if required
if(!mTouchBeforeAutoHide) {
// Send a delayed message to hide popup
mHandler.sendMessageDelayed(mHandler.obtainMessage(mDelayedMsgId),
mAutoHideDelay);
}
}
ViewGroup.LayoutParams lp;
for (PendingDismissData pendingDismiss : mPendingDismisses) {
// Reset view presentation
setAlpha(pendingDismiss.view, 1f);
setTranslationX(pendingDismiss.view, 0);
lp = pendingDismiss.view.getLayoutParams();
lp.height = originalHeight;
pendingDismiss.view.setLayoutParams(lp);
}
mPendingDismisses.clear();
}
}
});
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
lp.height = (Integer) valueAnimator.getAnimatedValue();
dismissView.setLayoutParams(lp);
}
});
mPendingDismisses.add(new PendingDismissData(dismissPosition, dismissView));
animator.start();
}
private void changePopupText() {
String msg = "";
if(mUndoActions.size() > 1 && mDeleteMultipleString != null) {
msg = String.format(mDeleteMultipleString, mUndoActions.size());
} else if(mUndoActions.size() >= 1) {
// Set title from single undoable or when no multiple deletion string
// is given
if(mUndoActions.get(mUndoActions.size() - 1).getTitle() != null) {
msg = mUndoActions.get(mUndoActions.size() - 1).getTitle();
} else {
msg = mDeleteString;
}
}
mUndoText.setText(msg);
}
private void changeButtonLabel() {
String msg;
if(mUndoActions.size() > 1 && mMode == UndoMode.COLLAPSED_UNDO) {
msg = mListView.getResources().getString(R.string.undoall);
} else {
msg = mListView.getResources().getString(R.string.undo);
}
mUndoButton.setText(msg);
}
/**
* Takes care of undoing a dismiss. This will be added as a
* {@link View.OnClickListener} to the undo button in the undo popup.
*/
private class UndoHandler implements View.OnClickListener {
public void onClick(View v) {
if(!mUndoActions.isEmpty()) {
switch(mMode) {
case SINGLE_UNDO:
mUndoActions.get(0).undo();
mUndoActions.clear();
break;
case COLLAPSED_UNDO:
Collections.reverse(mUndoActions);
for(Undoable undo : mUndoActions) {
undo.undo();
}
mUndoActions.clear();
break;
case MULTI_UNDO:
mUndoActions.get(mUndoActions.size() - 1).undo();
mUndoActions.remove(mUndoActions.size() - 1);
break;
}
}
// Dismiss dialog or change text
if(mUndoActions.isEmpty()) {
mUndoPopup.dismiss();
} else {
changePopupText();
changeButtonLabel();
}
mDelayedMsgId++;
}
}
/**
* Handler used to hide the undo popup after a special delay.
*/
private class HideUndoPopupHandler extends Handler {
@Override
public void handleMessage(Message msg) {
if(msg.what == mDelayedMsgId) {
// Call discard on any element
for(Undoable undo : mUndoActions) {
undo.discard();
}
mUndoActions.clear();
mUndoPopup.dismiss();
}
}
}
/**
* Enable/disable swipe.
*/
public void setSwipeDisabled(boolean disabled) {
this.mSwipeDisabled = disabled;
}
}
尽情享受吧!
关于android - 在 ListView 中实现滑动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17019359/
我怎样才能完成http://php.net/manual/en/function.call-user-func-array.php在ruby中?所以我可以这样做:classAppdeffoo(a,b)putsa+benddefbarargs=[1,2]App.send(:foo,args)#doesn'tworkApp.send(:foo,args[0],args[1])#doeswork,butdoesnotscaleendend 最佳答案 尝试分解数组App.send(:foo,*args)
我需要在RubyonRails中实现无向图G=(V,E)并考虑构建一个Vertex和一个Edge模型,其中Vertex有_多条边。由于边恰好连接两个顶点,您将如何在Rails中执行此操作?您是否知道任何有助于实现此类图表的gem或库(对重新发明轮子不感兴趣;-))? 最佳答案 不知道有任何现有库在ActiveRecord之上提供图形逻辑。您可能必须实现自己的Vertex、EdgeActiveRecord支持的模型(请参阅Rails安装的rails/activerecord中的vertex.rb和edge.rb/test/fixtur
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。问题1)我想知道rubyonrails是否有功能类似于primefaces的gem。我问的原因是如果您使用primefaces(http://www.primefaces.org/showcase-labs/ui/home.jsf),开发人员无需担心javascript或jquery的东西。据我所知,JSF是一个规范,基于规范的各种可用实现,prim
最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路
我haveaclass它公开了一个字符串值和一个int值(分别是命令输出和退出代码)。除了通过to_s和to_i公开它们之外,我还使用to_str和to_int,如下所示:classStatusdefto_s@outputendalias:to_str:to_sdefto_i@status.exitstatusendalias:to_int:to_iend我的想法是能够在尽可能多的情况下使用这个对象。将其强制转换为字符串或整数会增加可用性。例如,我可以将对象与字符串连接起来:a_string="Outputwas:"+results(我想用这个作为int强制转换的例子,但是Fixnum
我一直在尝试在Ruby中实现BinaryTree类,但我得到了stackleveltoodeep错误,尽管我似乎没有在该特定代码段中使用任何递归:1.classBinaryTree2.includeEnumerable3.4.attr_accessor:value5.6.definitialize(value=nil)7.@value=value8.@left=BinaryTree.new#stackleveltoodeephere9.@right=BinaryTree.new#andhere10.end11.12.defempty?13.(self.value==nil)?true:
来自Java,我正在尝试在Ruby中实现LinkedList。我在Java中实现它的通常方法是有一个名为LinkedList的类和一个名为Node的私有(private)内部类,其中LinkedList的每个对象都作为Node对象。classLinkedListprivateclassNodeattr_accessor:val,:nextendend我不想将Node类暴露给外部世界。然而,通过Ruby中的这个设置,我可以使用这个访问LinkedList类之外的私有(private)Node类对象-node=LinkedList::Node.new我知道,在Ruby1.9中,我们可以使用
我一直在尝试用Ruby实现Luhn算法。我一直在执行以下步骤:该公式根据其包含的校验位验证数字,该校验位通常附加到部分帐号以生成完整帐号。此帐号必须通过以下测试:从最右边的校验位开始向左移动,每第二个数字的值加倍。将乘积的数字(例如,10=1+0=1、14=1+4=5)与原始数字的未加倍数字相加。如果总模10等于0(如果总和以零结尾),则根据Luhn公式该数字有效;否则无效。http://en.wikipedia.org/wiki/Luhn_algorithm这是我想出的:defvalidCreditCard(cardNumber)sum=0nums=cardNumber.to_s.s
假设我有200个昂贵的方法调用(每个都有不同的参数)。出于某种原因,我可以并行执行其中的5个调用,但不能更多。我可以一次执行一个,但一次执行5个要快5倍。我想一直执行五件事。不想排五个,等五个都排完了,再排五个。如果我排队A、B、C、D、E并且C先完成,我想立即用F替换它,即使A和B还没有完成。我一直在研究这个问题,因为我可以想象它会定期发生。解决方案似乎是生产者-消费者模式,Ruby在其标准库中内置了一些用于该模式的结构(Queue和SizedQueue)。我玩过代码示例,阅读了一些文档,我想我对它有一个粗略的了解。但是我有一些问题我对我的解决方案没有信心,而且多线程的整个领域对我来
例如:a=[1,2,3,4,5]a.delete_if{|x|x>3}相当于:a=[1,2,3,4,5]a.delete_if.each.each.each.each{|x|x>3}我知道a.delete_if返回一个枚举器。但是当eachblock返回true时,它如何知道应该删除对象呢?如何手动(和在Ruby中)实现delete_if? 最佳答案 可以看看Rubinius源码:enumerablemodule这里是一个拒绝方法的例子:defrejectreturnto_enum(:reject)unlessblock_giv