首页 文章 精选 留言 我的

精选列表

搜索[网站开发],共10000篇文章
优秀的个人博客,低调大师

[android更新类的内容开发APP]四、项目布局的基本功能(继续)

昨天,只拿到电脑,别说,眼泪 http://joveth.github.io/funny/ 1.选项卡的滑动效果 要知道。用这个选项卡就是想让它滑动起来,不然的话。我才不喜欢用它呢。 在让他滑动之前,先来说一下上一张 的问题。话说。依照设计器下载下来的包,替换到 我们的 res之后,我发现,tabhost的选项颜色没有变,在我尝试 了各种方法之后,最终,我tm放弃了,好吧。正好 找到了这个滑动效果的demo,还有选项卡的颜色切换效果。 话不多说 ,改进我们的东西吧。 1.改动我们的 acitivity_main.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TabHost android:id="@+id/tab_host" android:layout_width="match_parent" android:layout_height="match_parent" > <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TabWidget android:id="@android:id/tabs" android:layout_width="match_parent" android:layout_height="48dp" android:background="@drawable/tab_widget_bg" /> <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="match_parent" /> <!-- 隐藏 --> <FrameLayout android:id="@android:id/tabcontent" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="gone" > <fragment android:id="@+id/fragment_image" android:name="com.jov.germany.frame.ImageFrame" android:layout_width="match_parent" android:layout_height="match_parent" /> <fragment android:id="@+id/fragment_text" android:name="com.jov.germany.frame.TextFrame" android:layout_width="match_parent" android:layout_height="match_parent" /> <fragment android:id="@+id/fragment_both" android:name="com.jov.germany.frame.BothFrame" android:layout_width="match_parent" android:layout_height="match_parent" /> </FrameLayout> </LinearLayout> </TabHost> </LinearLayout> 这里面加入了viewpage。还有把FramLayout隐藏了 当中的布局文件: res/color/tab_widget_text.xml <?xml version="1.0" encoding="utf-8"?> <!-- 标签页tab 文字切换颜色 --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_selected="true" android:color="@color/color_orange"/> <item android:color="#000"/> </selector> value/color.xml中加入: <color name="color_orange">#FF9224</color> 为啥是橘黄,我……假设你不喜欢,百度HTML颜色代码表,找一个你 自己的最爱 在来改动我们的 MainAcitivity.java package com.jov.germany; import java.util.ArrayList; import java.util.List; import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager.OnPageChangeListener; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.TabHost; import android.widget.TabHost.OnTabChangeListener; import android.widget.TabHost.TabContentFactory; import android.widget.TabHost.TabSpec; import android.widget.TextView; public class MainActivity extends FragmentActivity { public static final String PAGE1_ID = "page1"; public static final String PAGE2_ID = "page2"; public static final String PAGE3_ID = "page3"; private TabHost tabHost; // TabHost private List<View> views; // ViewPager内的View对象集合 private FragmentManager manager; // Activity管理器 private ViewPager pager; // ViewPager @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 初始化资源 pager = (ViewPager) findViewById(R.id.viewpager); tabHost = (TabHost) findViewById(R.id.tab_host); manager = getSupportFragmentManager(); views = new ArrayList<View>(); views.add(manager.findFragmentById(R.id.fragment_image).getView()); views.add(manager.findFragmentById(R.id.fragment_text).getView()); views.add(manager.findFragmentById(R.id.fragment_both).getView()); // 管理tabHost開始 tabHost.setup(); // 传一个空的内容给TabHost,不能用上面两个fragment TabContentFactory factory = new TabContentFactory() { @Override public View createTabContent(String tag) { return new View(MainActivity.this); } }; // tab1 TabSpec tabSpec = tabHost.newTabSpec(PAGE1_ID); tabSpec.setIndicator(createTabView(R.string.fragment_image_str)); tabSpec.setContent(factory); tabHost.addTab(tabSpec); // tab2 TabSpec tabSpec2 = tabHost.newTabSpec(PAGE2_ID); tabSpec2.setIndicator(createTabView(R.string.fragment_text_str)); tabSpec2.setContent(factory); tabHost.addTab(tabSpec2); // tab3 TabSpec tabSpec3 = tabHost.newTabSpec(PAGE3_ID); tabSpec3.setIndicator(createTabView(R.string.fragment_both_str)); tabSpec3.setContent(factory); tabHost.addTab(tabSpec3); tabHost.setCurrentTab(0); // 管理tabHost结束 // 设置监听器和适配器 pager.setAdapter(new PageAdapter()); pager.setOnPageChangeListener(new PageChangeListener()); tabHost.setOnTabChangedListener(new TabChangeListener()); } /** * PageView Adapter * * @author Administrator * */ private class PageAdapter extends PagerAdapter { @Override public int getCount() { return views.size(); } @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0 == arg1; } @Override public void destroyItem(ViewGroup view, int position, Object arg2) { view.removeView(views.get(position)); } @Override public Object instantiateItem(ViewGroup view, int position) { try { if (views.get(position).getParent() == null) { view.addView(views.get(position)); } else { ((ViewGroup) views.get(position).getParent()) .removeView(views.get(position)); view.addView(views.get(position)); } } catch (Exception e) { e.printStackTrace(); } return views.get(position); } } /** * 标签页点击切换监听器 * * @author Administrator * */ private class TabChangeListener implements OnTabChangeListener { @Override public void onTabChanged(String tabId) { if (PAGE1_ID.equals(tabId)) { pager.setCurrentItem(0); } else if (PAGE2_ID.equals(tabId)) { pager.setCurrentItem(1); } else if (PAGE3_ID.equals(tabId)) { pager.setCurrentItem(2); } } } /** * ViewPager滑动切换监听器 * * @author Administrator * */ private class PageChangeListener implements OnPageChangeListener { @Override public void onPageScrollStateChanged(int arg0) { } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { } @Override public void onPageSelected(int arg0) { tabHost.setCurrentTab(arg0); } } /** * 创建tab View * * @param string * @return */ private View createTabView(int stringId) { View tabView = getLayoutInflater().inflate(R.layout.tab, null); TextView textView = (TextView) tabView.findViewById(R.id.tab_text); textView.setText(stringId); return tabView; } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } } 当中的 layout/tab.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="@drawable/state_tabs_bg" > <TextView android:id="@+id/tab_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="11dp" android:layout_gravity="center_horizontal" android:textSize="18sp" android:textColor="@color/tab_widget_text"/> </LinearLayout> drawable/state_tabs_bg.xml <?xml version="1.0" encoding="utf-8"? > <!-- tab每一个标签背景 --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_selected="true" android:drawable="@drawable/tabs_selected_bg" /> <item android:drawable="@drawable/tabs_normal_bg"></item> </selector> drawable/tabs_selected_bg.xml <?xml version="1.0" encoding="UTF-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <item> <shape> <solid android:color="@color/color_orange" /> </shape> </item> <item android:bottom="5dp"> <shape> <solid android:color="#eeeeee" /> </shape> </item> </layer-list> drawable/tabs_normal_bg.xml <?xml version="1.0" encoding="UTF-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <item> <shape> <solid android:color="@color/color_orange" /> </shape> </item> <item android:bottom="1dp"> <shape> <solid android:color="#eeeeee" /> </shape> </item> </layer-list> 好至此的话 我们的代码算是ok了,可是当你执行的时候却发现跑不起来。为啥 呢??? 且看一下我们的Frame里面,改动 ImageFrame.java: package com.jov.germany.frame; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.jov.germany.R; public class ImageFrame extends Fragment{ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.image_frame, container, false); } } 你可能会认为没什么差别,看一下我们的Fragment引用的包,不一样哦。 好吧,最后 MainAcitivity.java中的String内容自己 在string.xml里面自己加把 没有截滑动效果。 近期各种忙,更新的 有点慢,没办法啊 源代码这里 版权声明:本文博客原创文章,博客,未经同意,不得转载。 本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/4651652.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

【Android UI设计与开发】8.顶部标题栏(一)ActionBar 奥义·详解

一、ActionBar介绍 在Android3.0中除了我们重点讲解的Fragment外,Action Bar也是一个非常重要的交互元素,Action Bar取代了传统的tittle bar和menu,在程序运行中一直置于顶部,对于Android平板设备来说屏幕更大它的标题使用Action Bar来设计可以展示更多丰富的内容,方便操控。 二、ActionBar的功能 用图的方式来讲解它的功能 <1> ActionBar的图标,可显示软件图标,也可用其他图标代替。当软件不在最高级页面时,图标左侧会显示一个左箭头,用户可以通过这个箭头向上导航; <2> 如果你的应用要在不同的View中显示数据,这部分允许用户来切换视图。一般的作法是用一个下拉菜单或者是Tab选项卡。如果只有一个界面,那这里可以显示应用程序的标题或者是更长一点的商标信息; <3> 两个action按钮,这里放重要的按钮功能,为用户进行某项操作提供直接的访问; <4> overflow按钮,放不下的按钮会被置于“更多...”菜单项中,“更多...”菜单项是以下拉形式实现的。 三、ActionBar 奥义·详解 1、添加ActionBar ActionBar的添加非常简单,只需要在AndroidManifest.xml中指定Application或Activity的theme是 Theme.Holo或其子类就可以了,在Android3.0及更高的版本中,Activity中都默认包含有ActionBar组件。 2、取消ActionBar 如果需要隐藏Action Bar可以在你的Activity的属性中设置主题风格为NoTitleBar在你的manifest文件中 <activity android:theme="@android:style/Theme.NoTitleBar"> 还有一种做法,在运行时调用hide()方法也可以隐藏ActionBar,调用show()方法来显示ActionBar()。 ActionBar actionBar = getActionBar(); actionBar.hide(); 当你隐藏ActionBar时,系统会将Activity的整个内容充满整个空间。 注意:如果使用一个主题(theme)来移除Activity上得ActionBar,那么窗口将不再会有ActionBar,因此在运行时也就没有办法来添加ActionBar——调用getActionBar()方法会返回null值。 3.修改Action Bar的图标和标题 默认情况下,系统会使用<application>或者<activity>中icon属性指定的图片来作为ActionBar 的图标,但是我们也可以改变这一默认行为。如果我们想要使用另外一张图片来作为ActionBar的图标,可以在<application> 或者<activity>中通过logo属性来进行指定,而标题中的内容使用label属性来指定。比如项目的res/drawable目录 下有一张cnblog_icon.png图片,就可以在AndroidManifest.xml中这样指定: <activity android:name=".MainActivity" android:label="召唤ActionBar吧" android:logo="@drawable/cnblog_icon" > 效果图如下: 4.添加Action按钮 ActionBar还可以根据应用程序当前的功能来提供与其相关的Action按钮,这些按钮都会以图标或文字的形式直接显示在ActionBar上。当 然,如果按钮过多,ActionBar上显示不完,多出的一些按钮可以隐藏在overflow里面(最右边的三个点就是overflow按钮),点击一下 overflow按钮就可以看到全部的Action按钮了。 当Activity启动的时候,系统会调用Activity的onCreateOptionsMenu()方法来取出所有的Action按钮,我们只需要在这个方法中去加载一个menu资源,并把所有的Action按钮都定义在资源文件里面就可以了。 那么我们先来看下menu资源文件该如何定义,代码如下所示: <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/user_p" android:icon="@drawable/icon_user_p" android:showAsAction="always" android:title="用户"/> <item android:id="@+id/write_p" android:icon="@drawable/icon_write_p" android:showAsAction="always" android:title="发布"/> <item android:id="@+id/favo_p" android:icon="@drawable/icon_favo_p" android:showAsAction="never" android:title="收藏"/> </menu> 可以看到,这里 我们通过两个<item>标签定义了三个Action按钮。<item>标签中又有一些属性,其中id是该Action按钮的唯 一标识符,icon用于指定该按钮的图标,title用于指定该按钮可能显示的文字(在图标能显示的情况下,通常不会显示文 字),actionViewClass用来指定一个构建视窗所使用的布局资源,showAsAction则指定了该按钮显示的位置,主要有以下几种值可 选: fRoom 会显示在Item中,但是如果已经有4个或者4个以上的Item时会隐藏在溢出列表中。当然个 数并不仅仅局限于4个,依据屏幕的宽窄而定 never 永远不会显示。只会在溢出列表中显示,而且只显示标题,所以在定义item的时候,最好 把标题都带上。 always 无论是否溢出,总会显示。 withText withText值示意Action bar要显示文本标题。Action bar会尽可能的显示这个 标题,但是,如果图标有效并且受到Action bar空间的限制,文本标题有可 能显示不全。 collapseActionView 声明了这个操作视窗应该被折叠到一个按钮中,当用户选择这个按钮时,这个操作视窗展开。否则, 这个操作视窗在默认的情况下是可见的,并且即便在用于不适用的时候,也要占据操作栏的有效空间。 一般要配合ifRoom一起使用才会有效果。 接着,重写Activity的onCreateOptionsMenu()方法,代码如下所示: @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu_main, menu); return super.onCreateOptionsMenu(menu); } 这部分代码很简单,仅仅是调用了MenuInflater的inflate()方法来加载menu资源就可以了。现在重新运行一下程序,结果如下图所示: 可以看到,menu_search和menu_setting这两个按钮已经在ActionBar中显示出来了,而menu_delete这个按钮由于 showAsAction属性设置成了never,所以被隐藏到了overflow当中,只要点击一下overflow按钮就可以看到它了。 这里我们注意到,显示在ActionBar上的按钮都只有一个图标而已,我们在title中指定的文字并没有显示出来。没错,title中的内容通常情况 下只会在overflow中显示出来,ActionBar中由于屏幕空间有限,默认是不会显示title内容的。但是出于以下几种因素考虑,即使 title中的内容无法显示出来,我们也应该给每个item中都指定一个title属性: 当ActionBar中的剩余空间不足的时候,如果Action按钮指定的showAsAction属性是ifRoom的话,该Action按钮就会出现在overflow当中,此时就只有title能够显示了。 如果Action按钮在ActionBar中显示,用户可能通过长按该Action按钮的方式来查看到title的内容。 5.响应Action按钮的点击事件 当用户点击 Action按钮的时候,系统会调用Activity的onOptionsItemSelected()方法,通过方法传入的MenuItem参数,我们 可以调用它的getItemId()方法和menu资源中的id进行比较,从而辨别出用户点击的是哪一个Action按钮,比如: @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.user_p: Toast.makeText(this, "你点击了“用户”按键!", Toast.LENGTH_SHORT).show(); return true; case R.id.write_p: Toast.makeText(this, "你点击了“发布”按键!", Toast.LENGTH_SHORT).show(); return true; case R.id.favo_p: Toast.makeText(this, "你点击了“收藏”按键!", Toast.LENGTH_SHORT).show(); return true; default: return super.onOptionsItemSelected(item); } } 可以看到,我们让每个Action按钮被点击的时候都弹出一个Toast,现在重新运行一下代码,结果如下图所示: 5.通过Action Bar图标进行导航 启用ActionBar图标导航的功能,可以允许用户根据当前应用的位置来在不同界面之间切换。比如,A界面展示了一个列表,点击某一项之后进入了B界面,这时B界面就应该启用ActionBar图标导航功能,这样就可以回到A界面。 我们可以通过调用setDisplayHomeAsUpEnabled()方法来启用ActionBar图标导航功能,比如: setTitle("Yanis"); setContentView(R.layout.activity_main); ActionBar actionBar = getActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); 现在重新运行一下程序,结果如下图所示: 可以看到,在ActionBar图标的左侧出现了一个向左的箭头,通常情况下这都表示返回的意思,因此最简单的实现就是在它的点击事件里面加入finish()方法就可以了,如下所示: switch (item.getItemId()) { case android.R.id.home: finish(); return true; ... } 当点击ActionBar图标的时候,系统同样会调用onOptionsItemSelected()方法,并且此时的itemId是android.R.id.home,所以finish()方法也就是加在这里的了。 现在看上去,ActionBar导航和Back键的功能貌似是一样的。没 错,如果我们只是简单地finish了一下,ActionBar导航和Back键的功能是完全一样的,但ActionBar导航的设计初衷并不是这样的, 它和Back键的功能还是有一些区别的,举个例子吧。 上图中的Conversation List是收件箱的主界面,现在我们点击第一封邮件会进入到Conversation1 details界面,然后点击下一封邮件会进入到Conversation 2 details界面,再点击下一封邮箱会进入到Conversation3 details界面。好的,这个时候如果我们按下Back键,应该会回到Conversation 2 details界面,再按一次Back键应该回到Conversation1 details界面,再按一次Back键才会回到Conversation List。而ActionBar导航则不应该表现出这种行为,无论我们当前在哪一个Conversation details界面,点击一下导航按钮都应该回到Conversation List界面才对。 这就是ActionBar导航和Back键在设计上的区别,那么该怎样才能实现这样的功能呢?其实并不复杂,实现标准的ActionBar导航功能只需三步走。 第一步我们已经实现了,就是调用setDisplayHomeAsUpEnabled()方法,并传入true。 第二步需要在AndroidManifest.xml中配置父Activity,如下所示: <activity android:name="com.yanis.actionbar.TabActivity"> <meta-data android:name="android.support.PARENT_ACTIVITY" android:value="com.yanis.actionbar.MainActivity" /> </activity> 可以看到,这里通过meta-data标签指定了MainActivity的父Activity是LaunchActivity,在Android 4.1版本之后,也可以直接使用android:parentActivityName这个属性来进行指定,如下所示: <activity android:name="com.yanis.actionbar.TabActivity" android:parentActivityName="com.yanis.actionbar.MainActivity" > </activity> 第三步则需要对android.R.id.home这个事件进行一些特殊处理,如下所示: @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: Intent upIntent = NavUtils.getParentActivityIntent(this); if (NavUtils.shouldUpRecreateTask(this, upIntent)) { TaskStackBuilder.create(this) .addNextIntentWithParentStack(upIntent) .startActivities(); } else { upIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); NavUtils.navigateUpTo(this, upIntent); } return true; ...... } } 其中,调用 NavUtils.getParentActivityIntent()方法可以获取到跳转至父Activity的Intent,然后如果父 Activity和当前Activity是在同一个Task中的,则直接调用navigateUpTo()方法进行跳转,如果不是在同一个Task中的, 则需要借助TaskStackBuilder来创建一个新的Task。 这样,就按照标准的规范成功实现ActionBar导航的功能了。 效果图如下: 6.添加Action View ActionView是一种可以在ActionBar中替换Action按钮的控件,它可以允许用户在不切换界面的情况下通过ActionBar完成一些较为丰富的操作。比如说,你需要完成一个搜索功能,就可以将SeachView这个控件添加到ActionBar中。 为了声明一个ActionView,我们可以在menu资源中通过actionViewClass属性来指定一个控件,还记得前面写过的吗: <item android:id="@+id/action_search" android:actionViewClass="android.widget.SearchView" android:showAsAction="always" android:title="搜索"/> 如果你还希望在代码中对SearchView的属性进行配置(比如添加监听事件等),完全没有问题,只需要在onCreateOptionsMenu()方法中获取该ActionView的实例就可以了,代码如下所示: @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.main, menu); MenuItem searchItem = menu.findItem(R.id.action_search); SearchView searchView = (SearchView) searchItem.getActionView(); // 配置SearchView的属性 ...... return super.onCreateOptionsMenu(menu); } 在得到了SearchView的实例之后,就可以任意地配置它的各种属性了。关于SearchView的更多详细用法,可以参考官方文档http://developer.android.com/guide/topics/search/search-dialog.html 除此之外,有些程序可能还希望在ActionView展开和合并的时候显示不同的界面,其实我们只需要去注册一个ActionView的监听器就能实现这样的功能了,代码如下所示: @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.main, menu); MenuItem searchItem = menu.findItem(R.id.action_search); searchItem.setOnActionExpandListener(new OnActionExpandListener() { @Override public boolean onMenuItemActionExpand(MenuItem item) { Log.d("TAG", "on expand"); return true; } @Override public boolean onMenuItemActionCollapse(MenuItem item) { Log.d("TAG", "on collapse"); return true; } }); return super.onCreateOptionsMenu(menu); } 可以看到,调用 MenuItem的setOnActionExpandListener()方法就可以注册一个监听器了,当SearchView展开的时候就会回调 onMenuItemActionExpand()方法,当SearchView合并的时候就会调用 onMenuItemActionCollapse()方法,我们在这两个方法中进行相应的UI操作就可以了。 7.Overflow按钮不显示的情况 虽然现在我们已 经掌握了不少ActionBar的用法,但是当你真正去使用它的时候还是可能会遇到各种各样的问题,比如很多人都会碰到overflow按钮不显示的情 况。明明是同样的一份代码,overflow按钮在有些手机上会显示,而在有些手机上偏偏就不显示,如下图: 可以看到,ActionBar最右边的overflow按钮不见,按一下Menu键,隐藏在overflow中的Action按钮就会从底部出来。 有人总结了一 下,overflow按钮的显示情况和手机的硬件情况是有关系的,如果手机没有物理Menu键的话,overflow按钮就可以显示,如果有物理Menu 键的话,overflow按钮就不会显示出来。比如我们启动一个有Menu键的模拟器,然后将代码运行到该模拟器上 实际上,在 ViewConfiguration这个类中有一个叫做sHasPermanentMenuKey的静态变量,系统就是根据这个变量的值来判断手机有没有 物理Menu键的。当然这是一个内部变量,我们无法直接访问它,但是可以通过反射的方式修改它的值,让它永远为false就可以了,代码如下所示: @Override protected void onCreate(Bundle savedInstanceState) { ...... setOverflowShowingAlways(); } private void setOverflowShowingAlways() { try { ViewConfiguration config = ViewConfiguration.get(this); Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey"); menuKeyField.setAccessible(true); menuKeyField.setBoolean(config, false); } catch (Exception e) { e.printStackTrace(); } } 这里我们在onCreate()方法的最后调用了setOverflowShowingAlways()方法,而这个方法的内部就是使用反射的方式将sHasPermanentMenuKey的值设置成false,现在重新运行一下代码,结果如下图所示: 可以看到,即使是在有Menu键的手机上,也能让overflow按钮显示出来了,这样就可以大大增加我们软件界面和操作的统一性。 8.让Overflow中的选项显示图标 如果你点击一下overflow按钮去查看隐藏的Action按钮,你会发现这部分Action按钮都是只显示文字不显示图标的,如下图所示: 这是官方的默认效果,Google认为隐藏在overflow中的Action按钮都应该只显示文字。当然,如果你认为这样不够美观,希望在overflow中的Action按钮也可以显示图标,我们仍然可以想办法来改变这一默认行为。 其实,overflow中的Action按钮应不应该显示图标,是由 MenuBuilder这个类的setOptionalIconsVisible变量来决定的,如果我们在overflow被展开的时候将这个变量赋值为 true,那么里面的每一个Action按钮对应的图标就都会显示出来了。赋值的方法当然仍然是用反射了,代码如下所示: @Override public boolean onMenuOpened(int featureId, Menu menu) { if (featureId == Window.FEATURE_ACTION_BAR && menu != null) { if (menu.getClass().getSimpleName().equals("MenuBuilder")) { try { Method m = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE); m.setAccessible(true); m.invoke(menu, true); } catch (Exception e) { } } } return super.onMenuOpened(featureId, menu); } 可以看到,这里我们重写了一个onMenuOpened()方法,当overflow被展开的时候就会回调这个方法,接着在这个方法的内部通过返回反射的方法将MenuBuilder的setOptionalIconsVisible变量设置为true就可以了。 现在重新运行一下代码,结果如下图所示: 9.添加Action Provider 和Action View有点类似,Action Provider也可以将一个Action按钮替换成一个自定义的布局。但不同的是,Action Provider能够完全控制事件的所有行为,并且还可以在点击的时候显示子菜单。 为了添加一个 Action Provider,我们需要在<item>标签中指定一个actionViewClass属性,在里面填入Action Provider的完整类名。我们可以通过继承ActionProvider类的方式来创建一个自己的Action Provider,同时,Android也提供好了几个内置的Action Provider,比如说ShareActionProvider。 由于每个Action Provider都可以自由地控制事件响应,所以它们不需要在onOptionsItemSelected()方法中再去监听点击事件,而是应该在onPerformDefaultAction()方法中去执行相应的逻辑。 那么我们就先来看一下ShareActionProvider的简单用法吧,编辑menu资源文件,在里面加入ShareActionProvider的声明,如下所示: <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/action_share" android:actionProviderClass="android.widget.ShareActionProvider" android:showAsAction="ifRoom" android:title="分享" /> ... </menu> 注意,ShareActionProvider会自己处理它的显示和事件,但我们仍然要记得给它添加一个title,以防止它会在overflow当中出现。 接着剩下的事情 就是通过Intent来定义出你想分享哪些东西了,我们只需要在onCreateOptionsMenu()中调用MenuItem的 getActionProvider()方法来得到该ShareActionProvider对象,再通过setShareIntent()方法去选择构 建出什么样的一个Intent就可以了。代码如下所示: @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu_main, menu); MenuItem shareItem = menu.findItem(R.id.action_share); ShareActionProvider provider = (ShareActionProvider) shareItem .getActionProvider(); provider.setShareIntent(getDefaultIntent()); return super.onCreateOptionsMenu(menu); } private Intent getDefaultIntent() { Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("image/*"); return intent; } 可以看到,这里我们通过getDefaultIntent()方法来构建了一个Intent,该Intent表示会将所有可以共享图片的程度都列出来。重新运行一下程序,效果如下图所示: 细心的你一定观察到了,这个ShareActionProvider点击之后是可以展开的,有点类似于overflow的效果,这就是Action Provider的子菜单。 10.添加导航Tabs Tabs的应用 可以算是非常广泛了,它可以使得用户非常轻松地在你的应用程序中切换不同的视图。而Android官方更加推荐使用ActionBar中提供的Tabs功 能,因为它更加的智能,可以自动适配各种屏幕的大小。比如说,在平板上屏幕的空间非常充足,Tabs会和Action按钮在同一行显示,如下图所示: 而如果是在手机上,屏幕的空间不够大的话,Tabs和Action按钮则会分为两行显示,如下图所示: 下面我们就来看一下如何使用ActionBar提供的Tab功能,大致可以分为以下几步: 1. 实现ActionBar.TabListener接口,这个接口提供了Tab事件的各种回调,比如当用户点击了一个Tab时,你就可以进行切换Tab的操作。 2.为每一个你想添加的Tab创建一个ActionBar.Tab的实例,并且调用setTabListener()方法来设置ActionBar.TabListener。除此之外,还需要调用setText()方法来给当前Tab设置标题。 3.最后调用ActionBar的addTab()方法将创建好的Tab添加到ActionBar中。 看起来并不复杂,总共就只有三步,那么我们现在就来尝试一下吧。首先第一步需要创建一个实现ActionBar.TabListener接口的类,代码如下所示: package com.yanis.yc_ui_actionbar_tab; import android.app.ActionBar; import android.app.ActionBar.Tab; import android.app.Activity; import android.app.Fragment; import android.app.FragmentTransaction; public class TabListener<T extends Fragment> implements ActionBar.TabListener { private Fragment mFragment; private final Activity mActivity; private final String mTag; private final Class<T> mClass; /** Constructor used each time a new tab is created. * @param activity The host Activity, used to instantiate the fragment * @param tag The identifier tag for the fragment * @param clz The fragment's Class, used to instantiate the fragment */ public TabListener(Activity activity, String tag, Class<T> clz) { mActivity = activity; mTag = tag; mClass = clz; } /* The following are each of the ActionBar.TabListener callbacks */ public void onTabSelected(Tab tab, FragmentTransaction ft) { // Check if the fragment is already initialized if (mFragment == null) { // If not, instantiate and add it to the activity mFragment = Fragment.instantiate(mActivity, mClass.getName()); ft.add(android.R.id.content, mFragment, mTag); } else { // If it exists, simply attach it in order to show it ft.attach(mFragment); } } public void onTabUnselected(Tab tab, FragmentTransaction ft) { if (mFragment != null) { // Detach the fragment, because another one is being attached ft.detach(mFragment); } } public void onTabReselected(Tab tab, FragmentTransaction ft) { // User selected the already selected tab. Usually do nothing. } } 这段代码并不 长,我们简单分析一下。当Tab被选中的时候会调用onTabSelected()方法,在这里我们先判断mFragment是否为空,如果为空的话就创 建Fragment的实例并调用FragmentTransaction的add()方法,如果不会空的话就调用FragmentTransaction 的attach()方法。 而当Tab没有被选中的时候,则调用FragmentTransaction的detach()方法,将UI资源释放掉。 当Tab被重新选中的时候会调用onTabReselected()方法,如果没有特殊需求的话,通常是不需要进行处理的。 接下来第二步要给每一个Tab创建一个ActionBar.Tab的实例,在此之前要先准备好每个Tab页对应的Fragment。比如说这里我们想创建三个Tab页,准备好这三个Tab页对应的Fragment和对应的布局文件。 package com.yanis.yc_ui_actionbar_tab; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; public class Fragment1 extends android.app.Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment1, container, false); } } 没有什么实质性的代码,只是显示了指定的布局文件。 Fragment都准备好了之后,接下来就可以开始创建Tab实例了,创建好了之后则再调用addTab()方法添加到ActionBar当中,这两步通常都是在Activity的onCreate()方法中执行的,代码如下: package com.yanis.actionbar; import android.app.ActionBar; import android.app.ActionBar.Tab; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.support.v4.app.NavUtils; import android.support.v4.app.TaskStackBuilder; import android.view.MenuItem; public class TabActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_tab); initView(); } private void initView() { // 提示getActionBar方法一定在setContentView后面 ActionBar actionBar = getActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); // 添加Tab选项 Tab tab = actionBar .newTab() .setText("澳门风云2") .setTabListener( new TabListener<Fragment1>(this, "film1", Fragment1.class)); actionBar.addTab(tab); tab = actionBar .newTab() .setText("五十度灰") .setTabListener( new TabListener<Fragment2>(this, "film2", Fragment2.class)); actionBar.addTab(tab); tab = actionBar .newTab() .setText("爸爸去哪儿2") .setTabListener( new TabListener<Fragment3>(this, "film3", Fragment3.class)); actionBar.addTab(tab); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: Intent upIntent = NavUtils.getParentActivityIntent(this); if (NavUtils.shouldUpRecreateTask(this, upIntent)) { TaskStackBuilder.create(this) .addNextIntentWithParentStack(upIntent) .startActivities(); } else { upIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); NavUtils.navigateUpTo(this, upIntent); } return true; default: return super.onOptionsItemSelected(item); } } } 可以看到,这里 是使用连缀的写法来创建Tab的。首先调用ActionBar的newTab()方法来创建一个Tab实例,接着调用了setText()方法来设置标 题,然后再调用setTabListener()方法来设置事件监听器,最后再调用ActionBar的addTab()方法将Tab添加到 ActionBar中。 好了,这样的话代码就编写完了,效果如下图所示: 11.添加下拉列表导航 1.1 简单介绍 作为Activity内部的另一种导航(或过滤)模式,操作栏提供了内置的下拉列表。下拉列表能够提供Activity中内容 的不同排序模式。 启用下拉式导航的基本过程如下: <1> 创建一个给下拉提供可选项目的列表,以及描画列表项目时所使用的布局; <2> 实现ActionBar.OnNavigationListener回调,在这个回调中定义当用户选择列表中一个项目时所发生的行为; <3> 用setNavigationMode()方法该操作栏启用导航模式; <4> 用setListNavigationCallbacks()方法给下拉列表设置回调方法。 1.2 效果图如下: 1.3 代码实现 ①准备列表数据( strings.xml) <string-array name="action_list"> <item>Fragment1</item> <item>Fragment2</item> <item>Fragment3</item> </string-array> ②然后就是主界面代码了 package com.yanis.actionbar; import android.app.ActionBar; import android.app.ActionBar.OnNavigationListener; import android.app.Activity; import android.app.Fragment; import android.app.TaskStackBuilder; import android.content.Intent; import android.os.Bundle; import android.support.v4.app.NavUtils; import android.view.MenuItem; import android.widget.ArrayAdapter; import android.widget.SpinnerAdapter; public class ListActivity extends Activity { private OnNavigationListener mOnNavigationListener; private String[] arry_list; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_list); initView(); } /** * 初始化组件 */ private void initView() { ActionBar actionBar = getActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); // //导航模式必须设为NAVIGATION_MODE_LIST actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); // 定义一个下拉列表数据适配器 SpinnerAdapter mSpinnerAdapter = ArrayAdapter.createFromResource(this, R.array.action_list, android.R.layout.simple_spinner_dropdown_item); arry_list = getResources().getStringArray(R.array.action_list); mOnNavigationListener = new OnNavigationListener() { @Override public boolean onNavigationItemSelected(int position, long itemId) { Fragment newFragment = null; switch (position) { case 0: newFragment = new Fragment1(); break; case 1: newFragment = new Fragment2(); break; case 2: newFragment = new Fragment3(); break; default: break; } getFragmentManager() .beginTransaction() .replace(R.id.container, newFragment, arry_list[position]).commit(); return true; } }; actionBar.setListNavigationCallbacks(mSpinnerAdapter, mOnNavigationListener); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: Intent upIntent = NavUtils.getParentActivityIntent(this); if (NavUtils.shouldUpRecreateTask(this, upIntent)) { TaskStackBuilder.create(this) .addNextIntentWithParentStack(upIntent) .startActivities(); } else { upIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); NavUtils.navigateUpTo(this, upIntent); } return true; default: return super.onOptionsItemSelected(item); } } } 12.自定义ActionBar样式 虽说ActionBar给用户提供了一种全局统一的界面风格和操作方式,但这并不意味着所有应用程序的ActionBar都必须要长得一模一样。如果你需要修改ActionBar的样式来更加好地适配你的应用,可以非常简单地通过Android样式和主题来实现。 其实Android内置的几个Activity主题中就已经包含了"dark"或"light"这样的ActionBar样式了,同时你也可以继承这些主题,然后进行更深一步的定制。 1. 使用主题 Android中有两个最基本的Activity主题可以用于指定ActionBar的颜色,分别是: Theme.Holo,这是一个深色系的主题。 Theme.Holo.Light,这是一个浅色系的主题。 深色系主题样式的效果如下图所示: 浅色系主题样式的效果如下图所示: 你可以将这些主题应用到你的整个应用程序,也可以只应用于某个 Activity。通过在AndroidManifest.xml文件中给<application>或<activity>标 签指定android:theme属性就可以实现了。比如: <application android:theme="@android:style/Theme.Holo.Light" ... /> 如果你只想让ActionBar使用深色系的主题,而Activity的内容部分仍然使用浅色系的主题,可以通过声明Theme.Holo.Light.DarkActionBar这个主题来实现,效果如下图所示: 2. 自定义背景 如果想要修改ActionBar的背景,我们可以通过创建一个自定义主题并 重写actionBarStyle属性来实现。这个属性可以指向另外一个样式,然后我们在这个样式中重写background这个属性就可以指定一个 drawable资源或颜色,从而实现自定义背景的功能。 编辑styles.xml文件,在里面加入一个自定义的主题,如下所示: <resources> <style name="CustomActionBarTheme" parent="@android:style/Theme.Holo.Light"> <item name="android:actionBarStyle">@style/MyActionBar</item> </style> <style name="MyActionBar" parent="@android:style/Widget.Holo.Light.ActionBar"> <item name="android:background">#f4842d</item> </style> </resources> 可以看到,这里 我们定义了一个CustomActionBarTheme主题,并让它继承自Theme.Holo.Light。然后在其内部重写了 actionBarStyle这个属性,然后将这个属性指向了MyActionBar这个样式,我们在这个样式中又重写了background属性,并给 它指定了一个背景色。 现在重新运行一下程序,效果如下图所示: 这样我们就成功修改ActionBar的背景色了。不过现在看上去还有点怪怪的,因为只是ActionBar的背景色改变了,Tabs的背景色还是原来的样子,这样就感觉不太协调。那么下面我们马上就来修改一下Tabs的背景色,编辑styles.xml文件,如下所示: <resources> <style name="CustomActionBarTheme" parent="@android:style/Theme.Holo.Light"> <item name="android:actionBarStyle">@style/MyActionBar</item> </style> <style name="MyActionBar" parent="@android:style/Widget.Holo.Light.ActionBar"> <item name="android:background">#f4842d</item> <item name="android:backgroundStacked">#d27026</item> </style> </resources> 可以看到,这里又重写了backgroundStacked属性,这个属性就是用于指定Tabs背景色的。那么再次重新运行程序,效果如下图所示: 3. 自定义文字颜色 现在整个ActionBar的颜色是属于偏暗系的,而ActionBar中文字的颜色又偏偏是黑色的,所以看起来并不舒服,那么接下来我们就学习一下如果自定义文字颜色,将文字颜色改成白色。 修改styles.xml文件,如下所示: <resources> ...... <style name="MyActionBar" parent="@android:style/Widget.Holo.Light.ActionBar"> ...... <item name="android:titleTextStyle">@style/MyActionBarTitleText</item> </style> <style name="MyActionBarTitleText" parent="@android:style/TextAppearance.Holo.Widget.ActionBar.Title"> <item name="android:textColor">#fff</item> </style> </resources> 可以看到,这里在MyActionBar样式里面重写了titleTextStyle属性,并将它指向了另一个自定义样式MyActionBarTitleText,接着我们在这个样式中指定textColor的颜色是#fff,也就是白色。 现在重新运行一下程序,结果如下图所示: OK,ActionBar标题文字的颜色已经成功改成白色了,那Tab标题的文字又该怎么修改呢?继续编辑styles.xml文件,如下所示: <resources> <style name="CustomActionBarTheme" parent="@android:style/Theme.Holo.Light"> <item name="android:actionBarStyle">@style/MyActionBar</item> <item name="android:actionBarTabTextStyle">@style/MyActionBarTabText</item> </style> <style name="MyActionBarTabText" parent="@android:style/Widget.Holo.ActionBar.TabText"> <item name="android:textColor">#fff</item> </style> </resources> 这里我们在CustomActionBarTheme主题中重写actionBarTabTextStyle属性,并将它指向一个新建的MyActionBarTabText样式,然后在这个样式中重写textColor属性,将颜色指定为白色即可。 重新运行一下程序,结果如下图所示: 4. 自定义Tab Indicator 为了可以明确分辨出我们当前选中的是哪一个Tab项,通常情况下都会在选中 Tab的下面加上一条横线作为标识,这被称作Tab Indicator。那么上图中的Tab Indicator是蓝色的,明显和整体风格不相符,所以我们接下来就学习一下如何自定义Tab Indicator。 首先我们需要重写actionBarTabStyle这个属性,然后将它指 向一个新建的Tab样式,然后重写background这个属性即可。需要注意的是,background必须要指定一个state-list drawable文件,这样在各种不同状态下才能显示出不同的效果。 那么在开始之前,首先我们需要准备四张图片,分别用于表示Tab的四种状态,如下所示: 这四张图片分别表示Tab选中未按下,选中且按下,未选中未按下,未选中且按下这四种状态,那么接着新建res/drawable/actionbar_tab_indicator.xml文件,代码如下所示: <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_selected="false" android:state_pressed="false" android:drawable="@drawable/tab_unselected" /> <item android:state_selected="true" android:state_pressed="false" android:drawable="@drawable/tab_selected" /> <item android:state_selected="false" android:state_pressed="true" android:drawable="@drawable/tab_unselected_pressed" /> <item android:state_selected="true" android:state_pressed="true" android:drawable="@drawable/tab_selected_pressed" /> </selector> 四种状态分别引用了四张图片,这样就把state-list drawable文件写好了。接着修改style.xml文件,代码如下所示: <resources> <style name="CustomActionBarTheme" parent="@android:style/Theme.Holo.Light"> ...... <item name="android:actionBarTabStyle">@style/MyActionBarTabs</item> </style> <style name="MyActionBarTabs" parent="@android:style/Widget.Holo.ActionBar.TabView"> <item name="android:background">@drawable/actionbar_tab_indicator</item> </style> </resources> 这里先是重写了actionBarTabStyle这个属性,并将它指向了另一个自定义样式MyActionBarTabs,接着在这个样式中重写background属性,然后指向我们刚才创建的actionbar_tab_indicator即可。 现在重新运行一下程序,效果如下所示: 可以看到,Tab Indicator的颜色已经变成了白色,这样看上去就协调得多了。 除此之外,Action Bar还有许许多多的属性可以进行自定义,这里我们无法一一涵盖到本篇文章中,更多的自定义属性请参考官方文档进行学习。 本文转自农夫山泉别墅博客园博客,原文链接:http://www.cnblogs.com/yaowen/p/5482331.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android UI开发第一篇——android的九宫格式实现

今天在devdiv论坛里看到有坛友问到九宫格的实现,我把我在项目中用的经验分享一下,九宫格用gridview实现代码如下:代码下载地址:http://www.devdiv.com/thread-39455-1-1.html xml代码: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res/com.google.android.gx5weather" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1.0" android:background="@drawable/bg" > <ImageView android:id="@+id/ImageView01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:background="@drawable/top"></ImageView> <GridView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/gridview" android:layout_width="wrap_content" android:layout_height="wrap_content" android:numColumns="3" android:verticalSpacing="30dip" android:horizontalSpacing="10dip" android:columnWidth="90dip" //列宽 android:stretchMode="columnWidth" android:gravity="center" android:listSelector="@drawable/grid_selector_background" > </GridView> </LinearLayout> android:numColumns="3" //九宫格的列数 auto_fit时为自动 android:listSelector="@drawable/grid_selector_background" //九宫格的背景,可以找个圆角正方形 public class NineBox extends Activity { /** Called when the activity is first created. */ @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); this.requestWindowFeature(Window.FEATURE_NO_TITLE); this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(R.layout.main_activity); GridView gridview=(GridView)findViewById(R.id.gridview); ArrayList<HashMap<String, Object>> lstImageItem = new ArrayList<HashMap<String, Object>>(); for(int i=1;i<10;i++) { HashMap<String, Object> map = new HashMap<String, Object>(); if(i==1){ map.put("ItemImage", R.drawable.g11); map.put("ItemText", getResources().getString(R.string.gridview1)); } if(i==2){ map.put("ItemImage", R.drawable.g12); map.put("ItemText", getResources().getString(R.string.gridview2)); } if(i==3){ map.put("ItemImage", R.drawable.g13); map.put("ItemText", getResources().getString(R.string.gridview3)); } if(i==4){ map.put("ItemImage", R.drawable.g14); map.put("ItemText", getResources().getString(R.string.gridview4)); } if(i==5){ map.put("ItemImage", R.drawable.g15); map.put("ItemText", getResources().getString(R.string.gridview5)); } if(i==6){ map.put("ItemImage", R.drawable.g16); map.put("ItemText", getResources().getString(R.string.gridview6)); } if(i==7){ map.put("ItemImage", R.drawable.g17); map.put("ItemText", getResources().getString(R.string.gridview7)); } if(i==8){ map.put("ItemImage", R.drawable.g18); map.put("ItemText", getResources().getString(R.string.gridview8)); } if(i==9){ map.put("ItemImage", R.drawable.g19); map.put("ItemText", getResources().getString(R.string.gridview9)); } lstImageItem.add(map); } SimpleAdapter saImageItems = new SimpleAdapter(this, lstImageItem, R.layout.grid_item, new String[] {"ItemImage","ItemText"}, new int[] {R.id.ItemImage,R.id.ItemText}); gridview.setAdapter(saImageItems); gridview.setOnItemClickListener(new ItemClickListener()); } class ItemClickListener implements OnItemClickListener { @SuppressWarnings("unchecked") public void onItemClick(AdapterView<?> arg0,//The AdapterView where the click happened View arg1,//The view within the AdapterView that was clicked int arg2,//The position of the view in the adapter long arg3//The row id of the item that was clicked ) { HashMap<String, Object> item=(HashMap<String, Object>) arg0.getItemAtPosition(arg2); if(item.get("ItemText").equals(getResources().getString(R.string.gridview1))){ Toast.makeText(NineBox.this, R.string.gridview1, Toast.LENGTH_LONG).show(); } if(item.get("ItemText").equals(getResources().getString(R.string.gridview2))){ Toast.makeText(NineBox.this, R.string.gridview2, Toast.LENGTH_LONG).show(); } if(item.get("ItemText").equals(getResources().getString(R.string.gridview3))){ Toast.makeText(NineBox.this, R.string.gridview3, Toast.LENGTH_LONG).show(); } if(item.get("ItemText").equals(getResources().getString(R.string.gridview4))){ Toast.makeText(NineBox.this, R.string.gridview4, Toast.LENGTH_LONG).show(); } if(item.get("ItemText").equals(getResources().getString(R.string.gridview5))){ Toast.makeText(NineBox.this, R.string.gridview5, Toast.LENGTH_LONG).show(); } if(item.get("ItemText").equals(getResources().getString(R.string.gridview6))){ Toast.makeText(NineBox.this, R.string.gridview6, Toast.LENGTH_LONG).show(); } if(item.get("ItemText").equals(getResources().getString(R.string.gridview7))){ Toast.makeText(NineBox.this, R.string.gridview7, Toast.LENGTH_LONG).show(); } if(item.get("ItemText").equals(getResources().getString(R.string.gridview8))){ Toast.makeText(NineBox.this, R.string.gridview8, Toast.LENGTH_LONG).show(); } if(item.get("ItemText").equals(getResources().getString(R.string.gridview9))){ Toast.makeText(NineBox.this, R.string.gridview9, Toast.LENGTH_LONG).show(); } } } } 本文转自xyz_lmn51CTO博客,原文链接:http://blog.51cto.com/xyzlmn/817400,如需转载请自行联系原作者

优秀的个人博客,低调大师

【Android UI设计与开发】10:滑动菜单栏(二)SlidingMenu 动画效果的实现

其实就是在显示菜单栏时,有个动画的效果。代码比较简单,下面进行说明。 1.效果图如下,手机上查看效果更佳 2.代码实现,这里只讲解动画效果的实现,具体代码可在源代码中查看 <1> 先定义一个CanvasTransformer接口对象,这个接口是在slidingmenu_library类库中封装好的 private CanvasTransformer mTransformer; <2> 然后再实例化此接口,重写接口中的方法,例如示例1中的方法: /** * transformCanvas(Canvas canvas, float percentOpen) * ① Canvas canvas:画布类; * ② float percentOpen:滑动菜单栏打开时的百分比值。 */ mTransformer = new CanvasTransformer() { @Override public void transformCanvas(Canvas canvas, float percentOpen) { float scale = (float) (percentOpen * 0.25 + 0.75); canvas.scale(scale, scale, canvas.getWidth() / 2, canvas.getHeight() / 2); } }; <3> 最后在把实例化的接口对象赋给SlidingMenu类中的setBehindCanvasTransformer()方法: getSlidingMenu().setBehindCanvasTransformer(mTransformer); <4>这样就完成了动画效果的实现,下面是示例1的主界面代码,其他的有兴趣的朋友可以查看源代码 package com.yanis.anima; import android.graphics.Canvas; import android.os.Bundle; import com.jeremyfeinstein.slidingmenu.lib.SlidingMenu; import com.jeremyfeinstein.slidingmenu.lib.SlidingMenu.CanvasTransformer; import com.jeremyfeinstein.slidingmenu.lib.app.SlidingFragmentActivity; /** * * @author Yanis * @Description 滑动时缩放的效果 */ public class FirstActivity extends SlidingFragmentActivity { private CanvasTransformer mTransformer; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initAnimation(); initSlidingMenu(); getActionBar().setDisplayHomeAsUpEnabled(true); } /** * 初始化滑动菜单 */ private void initSlidingMenu() { // 设置主界面视图 setContentView(R.layout.layout_right); // 设置滑动菜单视图 setBehindContentView(R.layout.layout_left); // 设置滑动菜单的属性值 SlidingMenu sm = getSlidingMenu(); // 根据dimension资源文件的ID来设置下方视图的偏移量,此处是220dp sm.setBehindOffsetRes(R.dimen.slidingmenu_offset); sm.setFadeDegree(0.35f); sm.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN); sm.setBehindScrollScale(0.0f); sm.setBehindCanvasTransformer(mTransformer); setSlidingActionBarEnabled(true); } /** * 初始化动画效果 */ private void initAnimation() { /** * transformCanvas(Canvas canvas, float percentOpen) * ① Canvas canvas:画布类; * ② float percentOpen:滑动菜单栏打开时的百分比值。 */ mTransformer = new CanvasTransformer() { @Override public void transformCanvas(Canvas canvas, float percentOpen) { float scale = (float) (percentOpen * 0.25 + 0.75); canvas.scale(scale, scale, canvas.getWidth() / 2, canvas.getHeight() / 2); } }; } } 本文转自叶超Luka博客园博客,原文链接:http://www.cnblogs.com/yc-755909659/p/4311173.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android GIS开发系列-- 入门季(7) 利用GeometryEngine坐标转换、计算距离与面积等

GeometryEngine是Arcgis的重要工具类,利用此工具类,可以计算地图上的距离、面积,将点、线、面转化为Json数据,将Json转化为点线面,坐标转换作用非常强大。 一、坐标转化 将用到方法 GeometryEngine.project(Geometry geometry, SpatialReference inputSR, SpatialReference outputSR),第二个为Geometry的坐标,第三个参数为要转换的坐标。如果将84坐标转换为墨卡托坐标代码如下: Point point1 = new Point(113,23); Point point2 =(Point)GeometryEngine.project(point1,SpatialReference.create(SpatialReference.WKID_WGS84), SpatialReference.create(SpatialReference.WKID_WGS84_WEB_MERCATOR)); 二、GeometryEngine计算两点的距离 用到 GeometryEngine.geodesicDistance(Geometry geometry1, Geometry geometry2, SpatialReference spatialReference, LinearUnit distanceUnit)方法。注意最好不要用GeometryEngine.distance方法,此方法是计算2D长度的,计算不准确。代码如下: Point point1 = new Point(113,23); Point point2 = new Point(113,24); double distance = GeometryEngine.geodesicDistance(point3,point4, SpatialReference.create(SpatialReference.WKID_WGS84), new LinearUnit(LinearUnit.Code.KILOMETER)); Log.i("TAG","distance ==="+distance );此外, 通过GeometryEngine.geodesicArea, GeometryEngine.geodesicLength可分别计算处面积和周长,大家去探索去。我有不想再列举了。 没有整理与归纳的知识,一文不值!高度概括与梳理的知识,才是自己真正的知识与技能。 永远不要让自己的自由、好奇、充满创造力的想法被现实的框架所束缚,让创造力自由成长吧! 多花时间,关心他(她)人,正如别人所关心你的。理想的腾飞与实现,没有别人的支持与帮助,是万万不能的。 本文转自wenglabs博客园博客,原文链接:http://www.cnblogs.com/arxive/p/7751954.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

[Android学习笔记三] Support v7提供交错式网格布局开发示例

本文主要介绍Android Support v7提供的RecycleView和交错式布局(通常成为瀑布流布局)的使用和事件监听处理。 1. 涉及到开源库有: Fresco: Facebook开源的不是一般强大的图片加载组件库 Bufferknife: Android View和事件绑定库,通过注解完成,在编译时APT处理注解文档。 2. 模块配置 Android Studio模块,build.gradle配置: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 applyplugin: 'com.android.application' android{ compileSdkVersion 21 buildToolsVersion '21.1.2' defaultConfig{ applicationId 'secondriver.sdk' minSdkVersion 16 targetSdkVersion 21 versionCode 1 versionName '1.0' } buildTypes{ release{ minifyEnabledfalse proguardFilesgetDefaultProguardFile( 'proguard-android.txt' ), 'proguard-rules.pro' } } packagingOptions{ exclude 'META-INF/services/javax.annotation.processing.Processor' } lintOptions{ disable 'InvalidPackage' } } dependencies{ compilefileTree(dir: 'libs' ,include:[ '*.jar' ]) compile 'com.android.support:appcompat-v7:21.0.3' compile 'com.android.support:recyclerview-v7:21.0.3@aar' compile 'com.android.support:cardview-v7:21.0.3@aar' compile 'com.facebook.fresco:fresco:0.8.0' compile 'com.jakewharton:butterknife:7.0.1' testCompile 'junit:junit:4.12' } 3. 布局文件 主布局文件:activity_recycleview.xml 包含一个RecycleView,将作为主屏幕组件。 1 2 3 4 5 6 7 8 9 10 11 12 13 <? xml version = "1.0" encoding = "utf-8" ?> < RelativeLayout android:id = "@+id/swipe_refresh_layout" xmlns:android = "http://schemas.android.com/apk/res/android" android:layout_width = "match_parent" android:layout_height = "wrap_content" > < android.support.v7.widget.RecyclerView android:id = "@+id/recycler_view" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:layout_alignParentTop = "true" android:scrollbars = "vertical" /> </ RelativeLayout > RecycleView 通过设置不同的布局管理器对象来实现不同的布局显示,如: android.support.v7.widget.LinearLayoutManager 可以实现ListView的布局效果 android.support.v7.widget.GridLayoutManager 可以实现GridView的布局效果 android.support.v7.widget.StaggeredGridLayoutManager 可以实现交错式网格布局效果 次布局文件(RecycleView中显示的每一项视图的布局):item_recycelview.xml 通过com.android.support:CardView包提供的CardView帧式容器布局包含一个ImageView和TextView作为RecycleView的每一项视图的布局。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 <? xml version = "1.0" encoding = "utf-8" ?> < LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android" xmlns:card_view = "http://schemas.android.com/apk/res-auto" xmlns:fresco = "http://schemas.android.com/tools" android:layout_width = "match_parent" android:layout_height = "match_parent" android:gravity = "center" > < android.support.v7.widget.CardView android:id = "@+id/card_view" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_gravity = "center" card_view:cardCornerRadius = "4dp" card_view:cardUseCompatPadding = "true" > < RelativeLayout android:layout_width = "match_parent" android:layout_height = "wrap_content" android:orientation = "vertical" > < com.facebook.drawee.view.SimpleDraweeView android:id = "@+id/info_image" android:layout_width = "300dp" android:layout_height = "420dp" fresco:actualImageScaleType = "centerCrop" fresco:placeholderImage = "@mipmap/ic_launcher" fresco:roundAsCircle = "false" fresco:roundBottomLeft = "true" fresco:roundBottomRight = "true" fresco:roundTopLeft = "true" fresco:roundTopRight = "true" fresco:roundedCornerRadius = "1dp" fresco:roundingBorderWidth = "2dp" /> < TextView android:id = "@+id/info_text" android:layout_width = "200dp" android:layout_height = "80dp" android:textSize = "20sp" android:textColor = "@android:color/holo_blue_dark" android:textAppearance = "?android:attr/textAppearanceMedium" android:layout_alignLeft = "@id/info_image" android:layout_alignRight = "@id/info_image" android:layout_below = "@id/info_image" android:gravity = "left|center_vertical" /> </ RelativeLayout > </ android.support.v7.widget.CardView > </ LinearLayout > ImageView组件使用的是Fresco库提供的视图组件。 4. Activity实现和数据填充 4.1 RecycleView中的每一项视图的数据组成 文本信息+ 图片地址(url,file,resId) 本示例中采用Url网络图片 1 2 3 4 5 6 7 8 9 10 11 12 /** *View项的数据对象 */ static class Pair{ public Stringtext; public Stringurl; public Pair(Stringtext,Stringurl){ this .text=text; this .url=url; } } 4.2 RecycleView中国的每一项视图的数据填充,即适配器 自定义适配器需要实现RecycleView.Adapter类。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 static class RecycleViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{ /** *RecycleView的View项单击事件监听 */ public interface OnRecycleViewItemClickListener{ void onRecycleViewItemClick(Viewview, int position); } private ArrayList<Pair>items= new ArrayList<>(); private OnRecycleViewItemClickListenermOnRecycleViewItemClickListener; public RecycleViewAdapter(ArrayList<Pair>items){ this .items=items; } @Override public RecyclerView.ViewHolderonCreateViewHolder(ViewGroupparent, int viewType){ Viewview=LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recyclerview,parent, false ); return new RecycleViewItemHolder(view,mOnRecycleViewItemClickListener); } @Override public void onBindViewHolder(RecyclerView.ViewHolderholder, int position){ Pairpair=items.get(position); ((RecycleViewItemHolder)holder).setContent(pair); } @Override public int getItemCount(){ return items.size(); } public void setOnRecycleViewItemClickListener(OnRecycleViewItemClickListeneronItemClickListener){ if ( null !=onItemClickListener){ this .mOnRecycleViewItemClickListener=onItemClickListener; } } } 主要实现onCreateViewHolder和onBindViewHolder方法。由于RecycleView并未提供为视图项添加监听事件,这里自定义个一个事件监听接口,在实例化适配器的时候可以选择设置事件监听。 4.3 创建ViewHolder需要通过自定义ViewHolder类继承RecycleView.ViewHolder。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 static class RecycleViewItemHolder extends RecyclerView.ViewHolder implements View.OnClickListener{ @Bind (R.id.info_text) public TextViewinfoTextView; @Bind (R.id.info_image) public SimpleDraweeViewdraweeView; private RecycleViewAdapter.OnRecycleViewItemClickListeneronItemClickListener; public RecycleViewItemHolder(ViewitemView,RecycleViewAdapter.OnRecycleViewItemClickListeneronItemClickListener){ super (itemView); ButterKnife.bind( this ,itemView); this .onItemClickListener=onItemClickListener; itemView.setOnClickListener( this ); } public void setContent(Pairpair){ infoTextView.setText(pair.text); draweeView.setImageURI(Uri.parse(pair.url)); } @Override public void onClick(Viewv){ if ( null !=onItemClickListener){ onItemClickListener.onRecycleViewItemClick(v,getPosition()); } } } 在构造方法中的传入OnRecycleViewItemClickListener对象,并且自定义ViewHolder实现OnClickListener接口,通过为itemView对象设置OnClickListener监听事件,在onClick方法中将点击事件的处理交由OnRecycleViewItemClickListener对象处理,从而达到为RecycleView中的itemView注册点击事件。 如果不采用这种方式添加事件监听,就不需要自定义监听接口和自定义ViewHolder实现事件监听接口以及事件处理。另外可以通过获得的itemView之后,通过组件I的获取组件来添加事件监听。还可以通过获得的自定义ViewHolder,来访问每个组件。 4.4 Activity的具体实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 package secondriver.sdk.activity; import android.app.Activity; import android.net.Uri; import android.os.Bundle; import android.support.v7.widget.DefaultItemAnimator; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.StaggeredGridLayoutManager; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import android.widget.Toast; import com.facebook.drawee.view.SimpleDraweeView; import java.util.ArrayList; import java.util.Arrays; import java.util.Random; import butterknife.Bind; import butterknife.ButterKnife; import secondriver.sdk.R; /** *Author:secondriver *Created:2015/11/18 */ public class RecycleViewActivity extends Activity{ private static final StringTAG=RecyclerView. class .getName(); private static final String[]RES_URL= new String[]{ "http://p1.wmpic.me/article/2015/11/16/1447644849_hySANEEF.jpg" , //减少篇幅,此处省去14个图片Url }; @Bind (R.id.recycler_view) public RecyclerViewmRecycleView; private final int PRE_SCREEN_NUMBER= 6 ; private final int SPAN_COUNT= 2 ; private int previousLastIndex= 0 ; private boolean isSlidingToLast= false ; private RecycleViewAdaptermAdapter; private ArrayList<Pair>mItem= new ArrayList<>(); //交错式网格布局管理对象,即通常称的瀑布流布局 private StaggeredGridLayoutManagermLayoutManager; @Override protected void onCreate(BundlesavedInstanceState){ super .onCreate(savedInstanceState); setContentView(R.layout.activity_recyclerview); ButterKnife.bind( this ); Fresco.initialize( this ); //重要,Fresco做一系列初始化工作 initRecycleView(); } private void initRecycleView(){ mLayoutManager= new StaggeredGridLayoutManager(SPAN_COUNT,StaggeredGridLayoutManager.VERTICAL); mRecycleView.setLayoutManager(mLayoutManager); mAdapter= new RecycleViewAdapter(mItem); loadData( false ); mRecycleView.setAdapter(mAdapter); mRecycleView.setItemAnimator( new DefaultItemAnimator()); //RecycleView的View项单击事件监听 mAdapter.setOnRecycleViewItemClickListener( new RecycleViewAdapter.OnRecycleViewItemClickListener(){ @Override public void onRecycleViewItemClick(Viewview, int position){ long id=mRecycleView.getChildItemId(view); Log.d(TAG, "View项的根视图:" +view.getClass().getName()+ ",position=" +position+ "ViewHolder_Id=" +id); //通过findViewById查找View项中的元素 SimpleDraweeViewdraweeView=(SimpleDraweeView)view.findViewById(R.id.info_image); if ( null !=draweeView){ draweeView.setImageURI(Uri.parse(RES_URL[ 0 ])); Toast.makeText(RecycleViewActivity. this , "通过findViewById查找View项中的元素" ,Toast.LENGTH_LONG).show(); } RecycleViewItemHolderrecycleViewItemHolder=(RecycleViewItemHolder)mRecycleView.findViewHolderForPosition(position); if ( null !=recycleViewItemHolder){ recycleViewItemHolder.infoTextView.setText( "通过ViewHolder找到View项中的元素" ); } } }); //下拉刷新,追加内容 mRecycleView.setOnScrollListener( new RecyclerView.OnScrollListener(){ @Override public void onScrollStateChanged(RecyclerViewrecyclerView, int newState){ super .onScrollStateChanged(recyclerView,newState); if (newState==RecyclerView.SCROLL_STATE_IDLE){ if (isPullToBottom()&&isSlidingToLast){ if (mItem.size()> 36 ){ //最大数据量 Toast.makeText(RecycleViewActivity. this , "没有数据了" ,Toast.LENGTH_LONG).show(); return ; } else { loadData( false ); Log.d(TAG, "notifyItemRangeInsertedstartPosition=" +previousLastIndex); mAdapter.notifyItemRangeInserted(previousLastIndex,PRE_SCREEN_NUMBER); } } } if (newState==RecyclerView.SCROLL_STATE_SETTLING){ Log.d(TAG, "settling" ); } } @Override public void onScrolled(RecyclerViewrecyclerView, int dx, int dy){ super .onScrolled(recyclerView,dx,dy); isSlidingToLast=dy> 0 ; //上拉,下滑 Log.d(TAG, "dx=" +dx+ "dy=" +dy+ "isSlidingToLast=" +isSlidingToLast); } } ); } private boolean isPullToBottom(){ int []lastIndexs=mLayoutManager.findLastCompletelyVisibleItemPositions( null ); Log.d(TAG, "lastitem=" +Arrays.toString(lastIndexs)+ ",haveitem=" +mAdapter.getItemCount()); int maxIndex=mAdapter.getItemCount()- 1 ; for ( int i:lastIndexs){ if (i==maxIndex){ return true ; } } return false ; } private void loadData( boolean isClear){ if (isClear){ mItem.clear(); } previousLastIndex=mItem.size(); Randomr= new Random(); for ( int index= 0 ;index<PRE_SCREEN_NUMBER&&index<RES_URL.length;index++){ mItem.add( new Pair( "Card" +(previousLastIndex+index),RES_URL[r.nextInt(RES_URL.length)])); } Log.d(TAG, "mItemcount=" +mItem.size()); } } 说明: RecycleView的ItemView的数据由Pair对象管理存储 Fresco库默认配置下的使用之前需要初始化调用Fresco.initialize(Context) 上述实现了2个事件监听,一个OnScrollerListener由RecycleView提供,实现下拉刷新;一个OnRecycleViewItemClickListener由自定义的RecycleViewAdpater提供,实现单击itemView来更换图片(SimpleDraweeView)和文字(TextView)。 Butterknife和Fresco库的具体使用参见其Github上的文档。 5. 效果图 比较遗憾ScreenRecord不支持模拟器和Android4.4一下的系统,只能附上截图。 本文转自 secondriver 51CTO博客,原文链接:http://blog.51cto.com/aiilive/1715139,如需转载请自行联系原作者

优秀的个人博客,低调大师

【Android游戏开发之六】在SurfaceView中添加组件!!!!并且相互交互数据!!!!

各位童鞋请你们注意:surfaceview中确实有 onDraw这个方法,但是surfaceview不会自己去调用!!! 而我代码中的ondraw 也好 draw 也好,都是我自己定义的一个方法。。。放在线程中不断调用的,一定要注意!! 昨天圣诞节,没有出去,而是一天时间全部纠结在如何在SurfaceView中添加组件,例如添加常用的Button,TextView等等、一开始也想着从网上找些资料看看有没有可参考的,但是发现搜到的结果仍是些童鞋对此很疑惑并且也在找寻答案,那么,这里就把圣诞节一天的成果来和各位童鞋分享; 1.因为我们的SurfaceView是个View对于添加的组件其实也是View,如果我们只是一味的想在SurfaceView中添加View组件其实是错误的思想,当然我一开始也是想着直接在SurfaceView中定义或者去使用组件,但是结果肯定是不成功的,因为View不能添加View! 2.既然第一条肯定是错误的,那么我们就应该想到把我们的SurfaceView和组件都放在一个Layout里面,毕竟我们的的SurfaceView也是一个view和其他组件一同放在我们的layout里,那么这样一来肯定就能完成在SurfaceView中添加组件的目的啦。下面先上截图 大家看到中间白色区域就是我们的SurfaceView啦,最上方是组件TextView ,最下方是Button 、对的,要的就是这个效果!而不是像前面文章中多个Activity切换,这样都在一个界面中啦。哇哈哈啊。好、下面来看代码吧: 先放上Xml 代码: <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <LinearLayout android:orientation="horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center"> <TextView android:id="@+id/textview" android:layout_width="fill_parent" android:layout_height="fill_parent" android:text="ThisisHimi" android:textSize="32sp" android:textColor="#00FF00" android:gravity="center_horizontal"/> </LinearLayout> <FrameLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1"> <com.himi.MySurfaceViewandroid:id="@+id/view3d" android:layout_width="fill_parent" android:layout_height="fill_parent"/> </FrameLayout> <LinearLayout android:orientation="horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="HimiButton_1" android:id="@+id/button1"/> <Buttonandroid:layout_width="wrap_content" android:layout_height="wrap_content" android:text="HimiButton_2" android:id="@+id/button2"/> </LinearLayout> </LinearLayout> 以上代码很简单,都是一些布局方式和各个组件一些属性及显示方式的设定,当然主要看如何对我们的SurfaceView如何注册在xml中的,那么每个组件都有id这样为了对后面其交互数据用到,因为我们要对每个组件操作,所以这里都索引了id方面从R文件中取出其对象。 那么,xml我们定义好了,看看代码中如何实现的,这里先说下Activity类中代码: packagecom.himi; importandroid.app.Activity; importandroid.os.Bundle; importandroid.view.View; importandroid.view.Window; importandroid.view.WindowManager; importandroid.view.View.OnClickListener; importandroid.widget.Button; importandroid.widget.TextView; publicclassMainActivityextendsActivityimplementsOnClickListener{ /**Calledwhentheactivityisfirstcreated.*/ privateButtonbutton1,button2; privateTextViewtv; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); this.requestWindowFeature(Window.FEATURE_NO_TITLE);//隐去标题(应用的名字) //此设定必须要写在setContentView之前,否则会有异常) this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(R.layout.main);//要先显示,然后再对其组件取出、处理操作 tv=(TextView)findViewById(R.id.textview); button1=(Button)findViewById(R.id.button1); button1.setOnClickListener(this);//这里是监听按键,因为本类使用了OnClickListener接口 button2=(Button)findViewById(R.id.button2); button2.setOnClickListener(this); /*其实大家也可以不用本类使用接口,可以内部类来完成。 *以下是不使用OnClickListener接口的绑定监听方式; button2.setOnClickListener(newOnClickListener(){ @Override publicvoidonClick(Viewv){ //这里处理按键操作 } }); */ } @Override publicvoidonClick(Viewv){ if(v==button1){ MySurfaceView.button_str="button1被触发"; tv.setText("button1被触发"); }elseif(v==button2){ MySurfaceView.button_str="button2被触发"; tv.setText("button2被触发"); } } } 该有的备注在代码后面都备注了,MySurfaceView.button_str,这个是自己的SurfaceView中定义的一个static 的变量用来交互数据用到;在那么下面就要看我们的SurfaceView,当在Xml注册需要注意什么了,我半天的时候都花在了这里!!!一定要引起注意,这也是在SurfaceView中并显示组件完成最重要的一步。 先分析: 1.SurfaceView类的创建和实现等等和之前都是一样的,该怎么去写还怎么去写,但是!构造函数一定要注意! /* *publicMySurfaceView(Contextcontext){super(context);}//备注1(这里一定要引起注意,仔细看下文对备注1的解释) */ publicMySurfaceView(Contextcontext,AttributeSetattrs){//备注1} 这里解释下备注1: 这里有两个构造函数,当然我们用哪个都是可以的,但是在此时我们需要明确我们到底要使用哪个。 一个参数的构造函数:如果是new出来的此类实例肯定是没有问题,但是我们为了能在显示SurfaceView同时显示别的组件,所以把自定义的SurfaceView也当作组件注册在了main——xml中,所以这里需要注意,当在xml中注册的就必须在SurfaceView中使用这种含有两个参数的构造函数的方法, xml初始化的时候会调用两个参数的这个构造方法, (当时这个问题困扰了半天的研究时间,最后在一个群友的帮助下才发现是这里出了问题) 那么含有两个构造参数的方法里第二个参数指的自定义的组件的一些属性,就像长宽一样,你可以给组件属性,就是通过这个来传递的! 那么在SurfaceView 中并一同显示组件也就到底完结了,回顾下,一共分为3步,1.将我们的SurfaceView 作为一个组件view 和其他组件一同放置到布局中,当然布局的方式和显示的方式大家自己随自己喜欢定义! 2.在我们的SurfaceView中一定要使用两个构造函数的构造函数,一定!一定! 就这里有区别,别的还是该怎么处理就怎么处理,就是构造函数换了 3.交互数据,对其按键的绑定在 activity中完成,别把view绑定在咱们的SurfaceView中啊,否则报错- -、 这里说下为什么要在activity中去绑定按键处理 而不是在我们的surfaceview中去绑定: 其实根据xml中定义button时的id 我们可以通过R.id 索引取到button,不管在activity中还是我们的surfaceview中都可以取到,但是!绑定button这一步如果在 surfaceview中去写就一定报错,原因我解释下; 我们在xml中定义我们的surfaceview 和 组件button、textview等等的时候 他们是同一级别的!!而不是把button包含在 surfaceview里,所以虽然在surfaceview中可以根据id索引到button但绑定的时候是无法找到button的,只有我们的activitysetContentView(R.layout.main); 显示的button,所以只能在显示它的activity中去绑定,这里需要注意下; 下面分享出源码: 源码下载地址:http://www.himigame.com/android-game/306.html 本文转自 xiaominghimi 51CTO博客,原文链接:http://blog.51cto.com/xiaominghimi/605740,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android UI开发第二十一篇——下拉刷新列表实现(pull to refresh)

android中提供了ListView控件,listview能够为我们展现丰富的内容,有时候我们为了提升用户体检,需要更炫而且更好用户体验的效果,pull to refresh(下拉刷新列表效果)就应运而生了。 pull to refresh更多的应用于获取最新的内容,比如新浪微博、腾讯微博等。目前网上有很多开源的pull to refresh的开源实现,这里也是参考开源代码实现的。 Layout <!-- The PullToRefreshListView replaces a standard ListView widget. --> <com.markupartist.android.widget.PullToRefreshListView android:id="@+id/android:list" android:layout_height="fill_parent" android:layout_width="fill_parent" /> Activity // Set a listener to be invoked when the list should be refreshed. ((PullToRefreshListView) getListView()).setOnRefreshListener(new OnRefreshListener() { @Override public void onRefresh() { // Do work to refresh the list here. new GetDataTask().execute(); } }); private class GetDataTask extends AsyncTask<Void, Void, String[]> { ... @Override protected void onPostExecute(String[] result) { mListItems.addFirst("Added after refresh..."); // Call onRefreshComplete when the list has been refreshed. ((PullToRefreshListView) getListView()).onRefreshComplete(); super.onPostExecute(result); } } 源码下载:http://download.csdn.net/detail/xyz_lmn/4676611 参考: https://github.com/johannilsson/android-pulltorefresh https://github.com/fanfoudroid/fanfoudroid http://www.eoeandroid.com/thread-190295-1-1.html http://k-beta.com/android-listview-more-refresh.html 本文转自xyz_lmn51CTO博客,原文链接:http://blog.51cto.com/xyzlmn/1230769,如需转载请自行联系原作者

优秀的个人博客,低调大师

Java微服务开发指南 -- 使用Docker和Kubernetes构建可伸缩的微服务

使用Docker和Kubernetes构建可伸缩的微服务 从现在开始,我们将从更高的维度讨论微服务,涵盖了组织敏捷性、设计和依赖的思考、领域驱动设计以及Promise理论。当我们深入使用之前介绍的三个流行的微服务框架:Spring Boot、Dropwizard和WildFly Swarm,我们能够使用它们开箱即用的能力去构建一个暴露或者消费REST服务的应用,能够使用外部环境对应用进行配置,可以打包成一个可执行的jar,同时提供Metrics信息,但这些都是围绕着一个微服务实例。当我们需要管理微服务之间的依赖、集群的启动和关闭、健康检查以及负载均衡的时候,我们使用微服务架构会面临什么问题呢?本章,我们将讨论这些高阶话题用来理解部署微服务时面对的挑战。 当我们开始将我们的应用和服务按照微服务的思路进行拆分后,我们将面临

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册