我的应用程序中有操作栏,它显示在我的 res/menu/activity_main.xml 中定义的菜单项
我的菜单项在操作栏上右对齐。我希望它们向左对齐。
我为这个使用过的自定义操作栏找到的唯一解决方案,比如这个: Positioning menu items to the left of the ActionBar in Honeycomb
但是,我不想为我的菜单创建自定义布局。我想使用从我的 res/menu/activity_main.xml 生成的默认菜单项。
这可能吗?
最佳答案
嗯,我对此很好奇,所以我深入挖掘了 SDK 的源代码。我在它的 XML 文件中使用了带有 3 个菜单项的 AppCompatActivity,并且我使用了默认的 onCreateOptionMenu 方法,它是这样的:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
在我使用调试器从 inflate 方法继续前进之后,我经历了以下堆栈:
updateMenuView():96, BaseMenuPresenter (android.support.v7.internal.view.menu)
updateMenuView():231, ActionMenuPresenter (android.support.v7.widget)
dispatchPresenterUpdate():284, MenuBuilder (android.support.v7.internal.view.menu)
onItemsChanged():1030, MenuBuilder (android.support.v7.internal.view.menu)
startDispatchingItemsChanged():1053, MenuBuilder (android.support.v7.internal.view.menu)
preparePanel():1303, AppCompatDelegateImplV7 (android.support.v7.app)
doInvalidatePanelMenu():1541, AppCompatDelegateImplV7 (android.support.v7.app)
access$100():92, AppCompatDelegateImplV7 (android.support.v7.app)
run():130, AppCompatDelegateImplV7$1 (android.support.v7.app)
handleCallback():739, Handler (android.os)
dispatchMessage():95, Handler (android.os)
loop():148, Looper (android.os)
main():5417, ActivityThread (android.app)
invoke():-1, Method (java.lang.reflect)
run():726, ZygoteInit$MethodAndArgsCaller (com.android.internal.os)
main():616, ZygoteInit (com.android.internal.os)
它结束于 BaseMenuPresenter 的 updateMenuView 方法,这是完成相关工作的地方。
方法代码:
public void updateMenuView(boolean cleared) {
final ViewGroup parent = (ViewGroup) mMenuView;
if (parent == null) return;
int childIndex = 0;
if (mMenu != null) {
mMenu.flagActionItems();
ArrayList<MenuItemImpl> visibleItems = mMenu.getVisibleItems();
final int itemCount = visibleItems.size();
for (int i = 0; i < itemCount; i++) {
MenuItemImpl item = visibleItems.get(i);
if (shouldIncludeItem(childIndex, item)) {
final View convertView = parent.getChildAt(childIndex);
final MenuItemImpl oldItem = convertView instanceof MenuView.ItemView ?
((MenuView.ItemView) convertView).getItemData() : null;
final View itemView = getItemView(item, convertView, parent);
if (item != oldItem) {
// Don't let old states linger with new data.
itemView.setPressed(false);
ViewCompat.jumpDrawablesToCurrentState(itemView);
}
if (itemView != convertView) {
addItemView(itemView, childIndex);
}
childIndex++;
}
}
}
// Remove leftover views.
while (childIndex < parent.getChildCount()) {
if (!filterLeftoverView(parent, childIndex)) {
childIndex++;
}
}
}
这里的 getItemView 和 addItemView 方法的作用与它们的名称相同。第一个膨胀一个新 View ,第二个将其添加到父 View 。更重要的是,在调试器下可以检查父对象,它是一个ActionMenuView。 , 它继承自 LinearLayout 和膨胀形式 abc_action_menu_layout.xml .
这意味着如果你能得到这个 View ,你就可以做你想做的事。从理论上讲,我认为可以通过大量反射(reflection)来完成,但这会很痛苦。 相反,您可以在您的代码中重现它。可以找到实现 here .
根据以上情况,你的问题的答案是肯定的,可以做到,但会很棘手。
编辑:
我通过反射(reflection)创建了一个概念证明。我用过 com.android.support:appcompat-v7:23.1.0。
我已经在模拟器(Android 6.0)和我的 Zuk Z1(CM Android 5.1.1)上试过了,两者都运行良好。
菜单 XML:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/action_settings" android:title="@string/action_settings"
android:orderInCategory="100" app:showAsAction="always" />
<item android:id="@+id/action_settings2" android:title="TEST1"
android:orderInCategory="100" app:showAsAction="always" />
<item android:id="@+id/action_settings3" android:title="TEST2"
android:orderInCategory="100" app:showAsAction="always" />
</menu>
Activity XML:
<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">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Button"
android:id="@+id/button"
android:layout_gravity="center_vertical" />
</LinearLayout>
Activity :
public class Main2Activity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//only a linear layout with one button
setContentView(R.layout.activity_main2);
Button b = (Button) findViewById(R.id.button);
// do the whole process for a click, everything is inited so we dont run into NPE
b.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AppCompatDelegate delegate = getDelegate();
Class delegateImpClass = null;
Field menu = null;
Method[] methods = null;
try {
//get objects based on the stack trace
delegateImpClass = Class.forName("android.support.v7.app.AppCompatDelegateImplV7");
//get delegate->mPreparedPanel
Field mPreparedPanelField = delegateImpClass.getDeclaredField("mPreparedPanel");
mPreparedPanelField.setAccessible(true);
Object mPreparedPanelObject = mPreparedPanelField.get(delegate);
//get delegate->mPreparedPanel->menu
Class PanelFeatureStateClass = Class.forName("android.support.v7.app.AppCompatDelegateImplV7$PanelFeatureState");
Field menuField = PanelFeatureStateClass.getDeclaredField("menu");
menuField.setAccessible(true);
Object menuObjectRaw = menuField.get(mPreparedPanelObject);
MenuBuilder menuObject = (MenuBuilder) menuObjectRaw;
//get delegate->mPreparedPanel->menu->mPresenter(0)
Field mPresentersField = menuObject.getClass().getDeclaredField("mPresenters");
mPresentersField.setAccessible(true);
CopyOnWriteArrayList<WeakReference<MenuPresenter>> mPresenters = (CopyOnWriteArrayList<WeakReference<MenuPresenter>>) mPresentersField.get(menuObject);
ActionMenuPresenter presenter0 = (ActionMenuPresenter) mPresenters.get(0).get();
//get the view from the presenter
Field mMenuViewField = presenter0.getClass().getSuperclass().getDeclaredField("mMenuView");
mMenuViewField.setAccessible(true);
MenuView menuView = (MenuView) mMenuViewField.get(presenter0);
ViewGroup menuViewParentObject = (ViewGroup) ((View) menuView);
//check the menu items count
int a = menuViewParentObject.getChildCount();
Log.i("ChildNum", a + "");
//set params as you want
Toolbar.LayoutParams params = (Toolbar.LayoutParams) menuViewParentObject.getLayoutParams();
params.gravity = Gravity.LEFT;
menuViewParentObject.setLayoutParams(params);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
}
虽然这里的重力已经改变,但在屏幕上这并没有产生任何相关的差异。要获得真正可见的变化,应调整其他布局参数(例如 width )。
总而言之,自定义布局更易于使用。
关于Android 将菜单项在操作栏中向左对齐,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12939085/
最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路
我有一个使用SeleniumWebdriver和Nokogiri的Ruby应用程序。我想选择一个类,然后对于那个类对应的每个div,我想根据div的内容执行一个Action。例如,我正在解析以下页面:https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=puppies这是一个搜索结果页面,我正在寻找描述中包含“Adoption”一词的第一个结果。因此机器人应该寻找带有className:"result"的div,对于每个检查它的.descriptiondiv是否包含单词“adoption
我正在我的Rails项目中安装Grape以构建RESTfulAPI。现在一些端点的操作需要身份验证,而另一些则不需要身份验证。例如,我有users端点,看起来像这样:moduleBackendmoduleV1classUsers现在如您所见,除了password/forget之外的所有操作都需要用户登录/验证。创建一个新的端点也没有意义,比如passwords并且只是删除password/forget从逻辑上讲,这个端点应该与用户资源。问题是Grapebefore过滤器没有像except,only这样的选项,我可以在其中说对某些操作应用过滤器。您通常如何干净利落地处理这种情况?
在我做的一些网络开发中,我有多个操作开始,比如对外部API的GET请求,我希望它们同时开始,因为一个不依赖另一个的结果。我希望事情能够在后台运行。我找到了concurrent-rubylibrary这似乎运作良好。通过将其混合到您创建的类中,该类的方法具有在后台线程上运行的异步版本。这导致我编写如下代码,其中FirstAsyncWorker和SecondAsyncWorker是我编写的类,我在其中混合了Concurrent::Async模块,并编写了一个名为“work”的方法来发送HTTP请求:defindexop1_result=FirstAsyncWorker.new.async.
a=[3,4,7,8,3]b=[5,3,6,8,3]假设数组长度相同,是否有办法使用each或其他一些惯用方法从两个数组的每个元素中获取结果?不使用计数器?例如获取每个元素的乘积:[15,12,42,64,9](0..a.count-1).eachdo|i|太丑了...ruby1.9.3 最佳答案 使用Array.zip怎么样?:>>a=[3,4,7,8,3]=>[3,4,7,8,3]>>b=[5,3,6,8,3]=>[5,3,6,8,3]>>c=[]=>[]>>a.zip(b)do|i,j|c[[3,5],[4,3],[7,6],
我有一个非常简单的Controller来管理我的Rails应用程序中的静态页面:classPagesController我怎样才能让View模板返回它自己的名字,这样我就可以做这样的事情:#pricing.html.erb#-->"Pricing"感谢您的帮助。 最佳答案 4.3RoutingParametersTheparamshashwillalwayscontainthe:controllerand:actionkeys,butyoushouldusethemethodscontroller_nameandaction_nam
1、接口请求基本操作1.1例子tips在view的选项可以zoomin调整窗口字帖大小。1、创建一个测试的workspace,并命名为test2、test后面新增一个addrequest3、选择发送GET,URL为一个开源的https://api.apiopen.top/api/sentences获取每日一句4、点击send查看内容Tips:如果提示出现Error:tunnelingsocketcouldnotbeestablished,statusCode=407错误,参照以下解决办法)关于tunnelingsocketcouldnotbeestablished,cause=getaddri
Linux操作系统——网络配置与SSH远程安装完VMware与系统后,需要进行网络配置。第一个目标为进行SSH连接,可以从本机到VMware进行文件传送,首先需要进行网络配置。1.下载远程软件首先需要先下载安装一款远程软件:FinalShell或者xhell7FinalShellxhell7FinalShell下载:Windows下载http://www.hostbuf.com/downloads/finalshell_install.exemacOS下载http://www.hostbuf.com/downloads/finalshell_install.pkg2.配置CentOS网络安装好
Ruby语言是否可以用于创建全新的移动操作系统或桌面操作系统,即是否可以用于系统编程? 最佳答案 嗯,现在有一些操作系统使用比C更高级的语言。基本上,ruby解释器本身需要用一些低级的东西来编写,并且需要一些引导加载代码将功能齐全的ruby解释器作为独立内核加载到内存中。一旦ruby解释器被引导并以内核模式(或innerrings之一)运行,就没有什么可以阻止您在其上构建整个操作系统。不幸的是,它可能会很慢。每个操作系统功能的垃圾收集可能会相当引人注目。ruby解释器将负责任务调度和网络堆栈等基本事情,使用垃圾收集框架会大大
假设我们有以下描述一个人的JSON对象:{"firstName":"John","lastName":"Smith","age":25,"address":{"streetAddress":"212ndStreet","city":"NewYork","state":"NY","postalCode":"10021"},"phoneNumber":[{"type":"home","number":"212555-1234"},{"type":"fax","number":"646555-4567"}]有人可以建议在Rails3中操作前一个对象的最优雅和最有效的方法吗?我希望能够:添加另