草庐IT

android 11 Launcher3去掉抽屉

Wang丶Yan 2024-06-03 原文

目录

前言

一、屏蔽上拉手势

二、将所有app加载至workspace

三、所有图标长按移动时顶部“移除”选项去掉

四、workspace中pageview指示横条换为圆点指示



前言

鉴于目前国内各大消费类手机都支持launcher左右滑动的这种标准桌面,google代码中为提供抽屉模式与标准模式的切换,所以我们在google源码的基础上修改launcher让其支持这种标准桌面。


一、屏蔽上拉手势

代码路径:packages\apps\Launcher3\quickstep\src\com\android\launcher3\uioverrides\touchcontrollers\PortraitStatesTouchController.java
 @Override
    protected boolean canInterceptTouch(MotionEvent ev) {
        //新增代码  屏蔽上拉手势  start
        if (true) {
            return false;
        }
        //新增代码  屏蔽上拉手势  end

        if (mCurrentAnimation != null) {
            if (mFinishFastOnSecondTouch) {
                mCurrentAnimation.getAnimationPlayer().end();
            }

            AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
            if (ev.getY() >= allAppsController.getShiftRange() * allAppsController.getProgress()) {
                // If we are already animating from a previous state, we can intercept as long as
                // the touch is below the current all apps progress (to allow for double swipe).
                return true;
            }
            // Otherwise, make sure everything is settled and don't intercept so they can scroll
            // recents, dismiss a task, etc.
            if (mAtomicAnim != null) {
                mAtomicAnim.end();
            }
            return false;
        }
        if (mLauncher.isInState(ALL_APPS)) {
            // In all-apps only listen if the container cannot scroll itself
            if (!mLauncher.getAppsView().shouldContainerScroll(ev)) {
                return false;
            }
        } else if (mLauncher.isInState(OVERVIEW)) {
            if (!mOverviewPortraitStateTouchHelper.canInterceptTouch(ev)) {
                return false;
            }
        } else {
            // If we are swiping to all apps instead of overview, allow it from anywhere.
            boolean interceptAnywhere = mLauncher.isInState(NORMAL) && !mAllowDragToOverview;
            // For all other states, only listen if the event originated below the hotseat height
            if (!interceptAnywhere && !isTouchOverHotseat(mLauncher, ev)) {
                return false;
            }
        }
        if (getTopOpenViewWithType(mLauncher, TYPE_ACCESSIBLE | TYPE_ALL_APPS_EDU) != null) {
            return false;
        }
        return true;
    }

二、将所有app加载至workspace

代码路径:

packages\apps\Launcher3\src\com\android\launcher3\model\PackageUpdatedTask.java

  @Override
    public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList appsList) {
       
		//....省略前面代码
        bindApplicationsIfNeeded();
        
        //新增 更新app到WorkSpace  start
        updateToWorkSpace(context,app,appsList);
        //新增 更新app到WorkSpace  end
		
		//....省略后面代码
        
    }
	
	
	//新增如下方法  start
    public void updateToWorkSpace(Context context, LauncherAppState app, AllAppsList appsList) {
        ArrayList<Pair<ItemInfo, Object>> installQueue = new ArrayList<>();
        UserManager mUserManager = context.getSystemService(UserManager.class);
        final List<UserHandle> profiles = mUserManager.getUserProfiles();
        ArrayList<InstallShortcutReceiver.PendingInstallShortcutInfo> added = new ArrayList<>();
        LauncherApps mLauncherApps = context.getSystemService(LauncherApps.class);
        for (UserHandle user : profiles) {
            final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null, user);
            synchronized (this) {
                for (LauncherActivityInfo info : apps) {
                    for (AppInfo appInfo : appsList.data) {
                           String packageName = info.getComponentName().getPackageName();
						   //Log.d(TAG, "updateToWorkSpace packageName :" + packageName+",appInfo.componentName:"+appInfo.componentName);
                        if (info.getComponentName().equals(appInfo.componentName)) {
                            InstallShortcutReceiver.PendingInstallShortcutInfo
                                    mPendingInstallShortcutInfo
                                    = new InstallShortcutReceiver.PendingInstallShortcutInfo(info, context);
                           //Log.e(TAG,"itemType :"+mPendingInstallShortcutInfo.getItemInfo().first.itemType);
                            added.add(mPendingInstallShortcutInfo);
                            installQueue.add(mPendingInstallShortcutInfo.getItemInfo());

                        }
                    }
                }
            }
        }
		 Log.d(TAG, "installQueue :" + installQueue.size());
        Log.d(TAG, "added.isEmpty() :" + added.isEmpty());
        if (!added.isEmpty()) {

            app.getModel().addAndBindAddedWorkspaceItems(installQueue);
        }
    }
	//新增如下方法  end

 以上代码只是将所有app获取到新增到WorkSpaceItems中,WorkSpaceItems中对于app还做了处理,看下面代码

代码路径:

packages\apps\Launcher3\src\com\android\launcher3\model\AddWorkspaceItemsTask.java

 @Override
    public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
        if (mItemList.isEmpty()) {
            return;
        }

        final ArrayList<ItemInfo> addedItemsFinal = new ArrayList<>();
        final IntArray addedWorkspaceScreensFinal = new IntArray();

        synchronized (dataModel) {
            IntArray workspaceScreens = dataModel.collectWorkspaceScreens();

            List<ItemInfo> filteredItems = new ArrayList<>();
            for (Pair<ItemInfo, Object> entry : mItemList) {
                ItemInfo item = entry.first;
                if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
                        item.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
                    // Short-circuit this logic if the icon exists somewhere on the workspace
                    if (shortcutExists(dataModel, item.getIntent(), item.user)) {
                        continue;
                    }

                    // b/139663018 Short-circuit this logic if the icon is a system app
                    //注释掉 该端代码  start
                   /* if (PackageManagerHelper.isSystemApp(app.getContext(), item.getIntent()) ) {
                        continue;
                    }*/
                    //注释掉 该端代码  end
					
					
					//...省略代码
                }

                //...省略代码
            }

           //...省略代码
        }
        
    }

三、所有图标长按移动时顶部“移除”选项去掉

1.去掉“移除”按钮

代码路径:

packages\apps\Launcher3\src\com\android\launcher3\DeleteDropTarget.java

修改如下:

  @Override
    protected boolean supportsDrop(ItemInfo info) {
       // 将 return true 修改为 return false;
        return false;
    }

2.DropTargetBar在去掉了“移除”按钮后,系统应用长按拖动会奔溃,我们需要在无按钮时DropTargetBar测量及绘制时重新给定宽和高

代码路径:

packages\apps\Launcher3\src\com\android\launcher3\DropTargetBar.java

  @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        if (getVisibleButtonsCount()>0){//新增显示的button数量判断,大于0才重新计算每个按钮的宽和高
            int width = MeasureSpec.getSize(widthMeasureSpec);
            int height = MeasureSpec.getSize(heightMeasureSpec);
            if (mIsVertical) {
                int widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
                int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);

                for (ButtonDropTarget button : mDropTargets) {
                    if (button.getVisibility() != GONE) {
                        button.setTextVisible(false);
                        button.measure(widthSpec, heightSpec);
                    }
                }
            } else {
                int visibleCount = getVisibleButtonsCount();
                int availableWidth = width / visibleCount;
                boolean textVisible = true;
                for (ButtonDropTarget buttons : mDropTargets) {
                    if (buttons.getVisibility() != GONE) {
                        textVisible = textVisible && !buttons.isTextTruncated(availableWidth);
                    }
                }

                int widthSpec = MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST);
                int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
                for (ButtonDropTarget button : mDropTargets) {
                    if (button.getVisibility() != GONE) {
                        button.setTextVisible(textVisible);
                        button.measure(widthSpec, heightSpec);
                    }
                }
            }
            setMeasuredDimension(width, height);
        }else{//新增显示的button数量判断,小于0给默认高度48
            int width = MeasureSpec.getSize(heightMeasureSpec);
            int height = 48;
            setMeasuredDimension(width, height);
        }

    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        if (getVisibleButtonsCount()>0) {  //新增显示的button数量判断,大于0才绘制
            if (mIsVertical) {
                int gap = getResources().getDimensionPixelSize(R.dimen.drop_target_vertical_gap);
                int start = gap;
                int end;

                for (ButtonDropTarget button : mDropTargets) {
                    if (button.getVisibility() != GONE) {
                        end = start + button.getMeasuredHeight();
                        button.layout(0, start, button.getMeasuredWidth(), end);
                        start = end + gap;
                    }
                }
            } else {
                int visibleCount = getVisibleButtonsCount();
                int frameSize = (right - left) / visibleCount;

                int start = frameSize / 2;
                int halfWidth;
                for (ButtonDropTarget button : mDropTargets) {
                    if (button.getVisibility() != GONE) {
                        halfWidth = button.getMeasuredWidth() / 2;
                        button.layout(start - halfWidth, 0,
                                start + halfWidth, button.getMeasuredHeight());
                        start = start + frameSize;
                    }
                }
            }
        }
    }

四、workspace中pageview指示横条换为圆点指示

1.布局文件替换

代码路径:

packages\apps\Launcher3\res\layout\launcher.xml

<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2007 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->
<com.android.launcher3.LauncherRootView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:launcher="http://schemas.android.com/apk/res-auto"
    android:id="@+id/launcher"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <com.android.launcher3.dragndrop.DragLayer
        android:id="@+id/drag_layer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipChildren="false"
        android:clipToPadding="false"
        android:importantForAccessibility="no">

        <!-- The workspace contains 5 screens of cells -->
        <!-- DO NOT CHANGE THE ID -->
        <com.android.launcher3.Workspace
            android:id="@+id/workspace"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="center"
            android:theme="@style/HomeScreenElementTheme"
            launcher:pageIndicator="@+id/page_indicator" />

        <!-- DO NOT CHANGE THE ID -->
        <include
            android:id="@+id/hotseat"
            layout="@layout/hotseat" />

        <include
            android:id="@+id/overview_panel"
            layout="@layout/overview_panel" />


        <!-- Keep these behind the workspace so that they are not visible when
         we go into AllApps -->
        <!-- com.android.launcher3.pageindicators.WorkspacePageIndicator替换为 com.android.launcher3.pageindicators.PageIndicatorDots-->
        <com.android.launcher3.pageindicators.PageIndicatorDots
            android:id="@+id/page_indicator"
            android:layout_width="match_parent"
            android:layout_height="@dimen/workspace_page_indicator_height"
            android:layout_gravity="bottom|center_horizontal"
            android:theme="@style/HomeScreenElementTheme" />

        <include
            android:id="@+id/drop_target_bar"
            layout="@layout/drop_target_bar" />

        <include
            android:id="@+id/scrim_view"
            layout="@layout/scrim_view" />

        <include
            android:id="@+id/apps_view"
            layout="@layout/all_apps"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </com.android.launcher3.dragndrop.DragLayer>

</com.android.launcher3.LauncherRootView>

2.WorkSpace继承修改

public class Workspace extends PagedView<WorkspacePageIndicator>
        implements DropTarget, DragSource, View.OnTouchListener,
        DragController.DragListener, Insettable, StateHandler<LauncherState>,
        WorkspaceLayoutManager
修改为
public class Workspace extends PagedView<PageIndicatorDots>  
        implements DropTarget, DragSource, View.OnTouchListener,
        DragController.DragListener, Insettable, StateHandler<LauncherState>,
        WorkspaceLayoutManager

3.修改左右滑动圆点指示的动画

代码路径:packages\apps\Launcher3\quickstep\src\com\android\launcher3\QuickstepAppTransitionManagerImpl.java

 /**
     * Content is everything on screen except the background and the floating view (if any).
     *
     * @param isAppOpening True when this is called when an app is opening.
     *                     False when this is called when an app is closing.
     * @param trans Array that contains the start and end translation values for the content.
     */
    private Pair<AnimatorSet, Runnable> getLauncherContentAnimator(boolean isAppOpening,
            float[] trans) {
        AnimatorSet launcherAnimator = new AnimatorSet();
        Runnable endListener;

        float[] alphas = isAppOpening
                ? new float[] {1, 0}
                : new float[] {0, 1};

        if (mLauncher.isInState(ALL_APPS)) {
           //省略代码...
        } else if (mLauncher.isInState(OVERVIEW)) {
            //省略代码...
        } else {
            //省略代码...

            // Pause page indicator animations as they lead to layer trashing.
            //注释该行代码
           // mLauncher.getWorkspace().getPageIndicator().pauseAnimations();

            endListener = () -> {
                currentPage.setTranslationY(0);
                hotseat.setTranslationY(0);
				
                currentPage.setLayerType(View.LAYER_TYPE_NONE, null);
                hotseat.setLayerType(View.LAYER_TYPE_NONE, null);
				
                
                mDragLayerAlpha.setValue(1f);
				//mLauncher.getWorkspace().getPageIndicator().skipAnimationsToEnd();修改为 mLauncher.getWorkspace().getPageIndicator().stopAllAnimations();
                mLauncher.getWorkspace().getPageIndicator().stopAllAnimations();
            };
        }
        return new Pair<>(launcherAnimator, endListener);
    }

4.修改PageIndicatorDots

代码路径:packages\apps\Launcher3\src\com\android\launcher3\pageindicators\PageIndicatorDots.java

PageIndicatorDots 实现Insettable

整体代码如下:

public class PageIndicatorDots extends View implements PageIndicator, Insettable {

    private static final float SHIFT_PER_ANIMATION = 0.5f;
    private static final float SHIFT_THRESHOLD = 0.1f;
    private static final long ANIMATION_DURATION = 150;

    private static final int ENTER_ANIMATION_START_DELAY = 300;
    private static final int ENTER_ANIMATION_STAGGERED_DELAY = 150;
    private static final int ENTER_ANIMATION_DURATION = 400;

    // This value approximately overshoots to 1.5 times the original size.
    private static final float ENTER_ANIMATION_OVERSHOOT_TENSION = 4.9f;

    private static final RectF sTempRect = new RectF();

    private static final Property<PageIndicatorDots, Float> CURRENT_POSITION
            = new Property<PageIndicatorDots, Float>(float.class, "current_position") {
        @Override
        public Float get(PageIndicatorDots obj) {
            return obj.mCurrentPosition;
        }

        @Override
        public void set(PageIndicatorDots obj, Float pos) {
            obj.mCurrentPosition = pos;
            obj.invalidate();
            obj.invalidateOutline();
        }
    };

    private final Paint mCirclePaint;
    private final float mDotRadius;
    private final int mActiveColor;
    private final int mInActiveColor;
    private final boolean mIsRtl;

    private int mNumPages;
    private int mActivePage;

    /**
     * The current position of the active dot including the animation progress.
     * For ex:
     * 0.0  => Active dot is at position 0
     * 0.33 => Active dot is at position 0 and is moving towards 1
     * 0.50 => Active dot is at position [0, 1]
     * 0.77 => Active dot has left position 0 and is collapsing towards position 1
     * 1.0  => Active dot is at position 1
     */
    private float mCurrentPosition;
    private float mFinalPosition;
    private ObjectAnimator mAnimator;

    private float[] mEntryAnimationRadiusFactors;
    //wangyan
    private Launcher mLauncher;

    public PageIndicatorDots(Context context) {
        this(context, null);
    }

    public PageIndicatorDots(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public PageIndicatorDots(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mCirclePaint.setStyle(Style.FILL);
        mDotRadius = getResources().getDimension(R.dimen.page_indicator_dot_size) / 2;
        setOutlineProvider(new MyOutlineProver());

        //选中与未选中的颜色修改
        mActiveColor = Color.parseColor("#ffffff");///Themes.getColorAccent(context);
        mInActiveColor = Color.parseColor("#c6c5c5");  //Themes.getAttrColor(context, android.R.attr.colorControlHighlight);

        mIsRtl = Utilities.isRtl(getResources());
        //wangyan
        mLauncher = Launcher.getLauncher(context);
    }

    //新增实现方法 start
    @Override
    public void setInsets(Rect insets) {
        DeviceProfile grid = mLauncher.getDeviceProfile();
        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();

        if (grid.isVerticalBarLayout()) {
            Rect padding = grid.workspacePadding;
            lp.leftMargin = padding.left + grid.workspaceCellPaddingXPx;
            lp.rightMargin = padding.right + grid.workspaceCellPaddingXPx;
            lp.bottomMargin = padding.bottom;
        } else {
            lp.leftMargin = lp.rightMargin = 0;
            lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
            lp.bottomMargin = grid.hotseatBarSizePx + insets.bottom;
        }
        setLayoutParams(lp);
    }
    //新增实现方法 end

    @Override
    public void setScroll(int currentScroll, int totalScroll) {
        if (mNumPages > 1) {
            if (mIsRtl) {
                currentScroll = totalScroll - currentScroll;
            }
            int scrollPerPage = totalScroll / (mNumPages - 1);

            //wangyan
            if (scrollPerPage == 0) {
                return;
            }
            int pageToLeft = currentScroll / scrollPerPage;
            int pageToLeftScroll = pageToLeft * scrollPerPage;
            int pageToRightScroll = pageToLeftScroll + scrollPerPage;

            float scrollThreshold = SHIFT_THRESHOLD * scrollPerPage;
            if (currentScroll < pageToLeftScroll + scrollThreshold) {
                // scroll is within the left page's threshold
                animateToPosition(pageToLeft);
            } else if (currentScroll > pageToRightScroll - scrollThreshold) {
                // scroll is far enough from left page to go to the right page
                animateToPosition(pageToLeft + 1);
            } else {
                // scroll is between left and right page
                animateToPosition(pageToLeft + SHIFT_PER_ANIMATION);
            }
        }
    }

    //....省略部分代码
}

至此android 11 Launcher3 去掉抽屉模式修改完成。有什么问题可以给我留言。 

有关android 11 Launcher3去掉抽屉的更多相关文章

  1. ruby - 安装libv8(3.11.8.13)出错,Bundler无法继续 - 2

    运行bundleinstall后出现此错误:Gem::Package::FormatError:nometadatafoundin/Users/jeanosorio/.rvm/gems/ruby-1.9.3-p286/cache/libv8-3.11.8.13-x86_64-darwin-12.gemAnerroroccurredwhileinstallinglibv8(3.11.8.13),andBundlercannotcontinue.Makesurethat`geminstalllibv8-v'3.11.8.13'`succeedsbeforebundling.我试试gemin

  2. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  3. ruby - ri 有空文件 – Ubuntu 11.10, Ruby 1.9 - 2

    我正在运行Ubuntu11.10并像这样安装Ruby1.9:$sudoapt-getinstallruby1.9rubygems一切都运行良好,但ri似乎有空文档。ri告诉我文档是空的,我必须安装它们。我执行此操作是因为我读到它会有所帮助:$rdoc--all--ri现在,当我尝试打开任何文档时:$riArrayNothingknownaboutArray我搜索的其他所有内容都是一样的。 最佳答案 这个呢?apt-getinstallri1.8编辑或者试试这个:(非rvm)geminstallrdocrdoc-datardoc-da

  4. ruby - rails 3.2.2(或 3.2.1)+ Postgresql 9.1.3 + Ubuntu 11.10 连接错误 - 2

    我正在使用PostgreSQL9.1.3(x86_64-pc-linux-gnu上的PostgreSQL9.1.3,由gcc-4.6.real(Ubuntu/Linaro4.6.1-9ubuntu3)4.6.1,64位编译)和在ubuntu11.10上运行3.2.2或3.2.1。现在,我可以使用以下命令连接PostgreSQLsupostgres输入密码我可以看到postgres=#我将以下详细信息放在我的config/database.yml中并执行“railsdb”,它工作正常。开发:adapter:postgresqlencoding:utf8reconnect:falsedat

  5. ruby-on-rails - Rails 2.3.11 DateTime BigDecimal 精度 - 2

    我目前有一个运行Ruby1.8.7和Rails2.3.2的RubyonRails项目我有一些从数据库中读取数据的单元测试,特别是两个连续项目的日期时间列,这两个项目应该相隔24小时。在一项测试中,我将项目2的日期时间设置为与项目1的日期时间相同。当我执行断言以确保两个值相等时,测试在rails2.3.2下工作正常。当我升级到rails2.3.11时,测试失败显示两次之间的差异将关闭并出现以下错误:expectedbutwas.这两个版本的rails中似乎存在浮点转换问题。如何解决float问题? 最佳答案 这也发生在我身上,我最终这

  6. Win10 / 11新电脑最简单跳过联网激活和使用本地账户登录方法 - 2

    跳过联网激活:OOBE界面直接按Ctrl+Shift+F3进入审核模式。这样就可以直接进入系统进行一些硬件测试等,而不用联网激活导致新机无法退货。需要注意的是,在审核模式下进行的一些操作都会保留,并不会在退出后自动还原!安装的软件在正常开机进系统后还会看见!如果电脑确实没连互联网又不想强行跳过OOBE(网上很多教程会叫你直接结束OOBE进程,但这是不推荐的,因为一些厂商自带优化程序和系统初始化设置在后面都会应用,对于笔记本跳过的话你会发现驱动和内置应用都没有装上。其实这部分脚本就在系统盘的Recovery隐藏文件夹下),可以参考以下方式:https://www.landiannews.com/

  7. ruby-on-rails - 在 El Capitan 上安装 Rails 时出现 -lgmp 错误的库未找到(Mac OS 10.11.1 (15B42)) - 2

    在使用Rubyv2.2.2的ElCapitan(MacOSX10.11.1)上安装Rails时,出现以下错误:ERROR:Errorinstallingnokogiri:ERROR:Failedtobuildgemnativeextension./Users/jon/.rvm/rubies/ruby-2.2.2/bin/ruby-r./siteconf20151117-26799-ux15fd.rbextconf.rb--use-system-librariescheckingiftheCcompileraccepts...***extconf.rbfailed***Couldnotc

  8. ruby-on-rails - Rails 3.2.11 突然需要重启到 'acknowledge' Controller 有什么变化吗? - 2

    标题说明了一切。请注意,这不是模型或初始值设定项的更改。我可以删除Controller中的一个实例变量(例如,@user),然后重新加载一个View,它会工作-直到我重新启动服务器,在这种情况下它会提示变量为nil。我正常工作,然后切换到一组完全不同的Controller和View上工作,现在它无缘无故地发生了。应用处于开发环境中。development.rb内容:Dashboard::Application.configuredoconfig.cache_classes=falseconfig.whiny_nils=trueconfig.consider_all_requests_l

  9. ruby - 使用 ruby​​ 1.9.3 在 Ubuntu 11.10 上安装 ruby​​-rvm - 2

    rvm通过以下方式正确安装:sudoapt-get安装ruby​​-rvm当我尝试安装ruby​​1.9.3时出现这些错误?anthony@SnakeDoc:~$rvminstall1.9.3mkdir:cannotcreatedirectory`/usr/share/ruby-rvm/gems/ruby-1.9.3-p0':PermissiondeniedInstallingRubyfromsourceto:/usr/share/ruby-rvm/rubies/ruby-1.9.3-p0,thismaytakeawhiledependingonyourcpu(s)...ruby-1.

  10. ruby - 安装 libv8 3.11.8.3 时出错 - 2

    我正在运行全新安装的OSX10.9Mavericks和XCode5.0.1。当我尝试在我的项目中运行bundleinstall时,它无法安装libv8gem。这是输出:ERROR:Errorinstallinglibv8:ERROR:Failedtobuildgemnativeextension./Users/user1/.rvm/rubies/ruby-1.9.3-p448/bin/rubyextconf.rbcreatingMakefileConfiguredwith:--prefix=/Applications/Xcode.app/Contents/Developer/usr--

随机推荐