当前位置:  编程技术>移动开发
本页文章导读:
    ▪高仿iReader书架成效        高仿iReader书架效果   [html] view plaincopy <?xml version="1.0" encoding="utf-8"?>   <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"       android:layout_width="fill_parent"       an.........
    ▪ 在map下默认显示注解,不用点击大头针就出来        在地图上默认显示注解,不用点击大头针就出来 - (void)viewDidAppear:(BOOL)animated{    [super viewDidAppear:animated];    [self addRestaurantAnnotation];}      //下面一句话使得注解初始在上面显示。    [se.........
    ▪ (通译) Backward Compatibility for Applications       (翻译) Backward Compatibility for Applications 原文来自Android SDK文档中的 docs/resources/articles/backward-compatibility.html   目前有各种Android设备。 这些设备使用不同的Android版本, 有些运行最新的版本, .........

[1]高仿iReader书架成效
    来源: 互联网  发布时间: 2014-02-18
高仿iReader书架效果

 

 阅读过电子书的朋友相信对iReader都是比较熟悉的,iReader的书架做的非常漂亮,以前总以为是使用了2D画图做的呢,今天反编译了一下才明白原来是用图片拼接起来的,这样就OK了,今天我就带大家实现一个iReader书架。

         首先看一下layout下main.xml布局:

 

[html] view plaincopy
  • <?xml version="1.0" encoding="utf-8"?>  
  • <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  •     android:layout_width="fill_parent"  
  •     android:layout_height="fill_parent"  
  •     android:orientation="vertical" >  
  •   
  •     <RelativeLayout  
  •         android:layout_width="fill_parent"  
  •         android:layout_height="wrap_content"  
  •         android:background="@drawable/bookshelf_header_bg" >  
  •   
  •         <ImageView  
  •             android:id="@+id/shelf_image_title"  
  •             android:layout_width="wrap_content"  
  •             android:layout_height="wrap_content"  
  •             android:layout_centerInParent="true"  
  •             android:background="@drawable/bookshelf_header_logo" />  
  •   
  •         <Button  
  •             android:id="@+id/shelf_image_button"  
  •             android:layout_width="wrap_content"  
  •             android:layout_height="wrap_content"  
  •             android:layout_alignParentRight="true"  
  •             android:background="@drawable/bookshelf_goto_bookcity_f" />  
  •     </RelativeLayout>  
  •   
  •     <ListView  
  •         android:id="@+id/shelf_list"  
  •         android:layout_width="fill_parent"  
  •         android:layout_height="fill_parent"  
  •         android:scrollbars="none"  
  •         android:divider="#00000000"  
  •         android:cacheColorHint="#00000000"/>  
  •   
  • </LinearLayout>  

  •       由于书架是用图片拼成的,所以每一个行的数据框都是一个listview ,  看一些listview对应的item布局:

     

     

    [html] view plaincopy
  • <?xml version="1.0" encoding="utf-8"?>  
  • <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  •     android:layout_width="fill_parent"  
  •     android:layout_height="fill_parent" >  
  •   
  •     <ImageView  
  •         android:id="@+id/shelf_image_left"  
  •         android:layout_width="wrap_content"  
  •         android:layout_height="wrap_content"  
  •         android:layout_alignParentLeft="true"  
  •         android:layout_centerVertical="true"  
  •         android:background="@drawable/bookshelf_layer_left" />  
  •   
  •     <LinearLayout  
  •         android:id="@+id/linearLayout1"  
  •         android:layout_width="wrap_content"  
  •         android:layout_height="wrap_content"  
  •         android:layout_centerVertical="true"  
  •         android:layout_toLeftOf="@+id/shelf_image_right"  
  •         android:layout_toRightOf="@+id/shelf_image_left"  
  •         android:background="@drawable/bookshelf_layer_center"  
  •         android:orientation="horizontal" >  
  •   
  •         <LinearLayout  
  •             android:layout_width="wrap_content"  
  •             android:layout_height="wrap_content"  
  •             android:layout_weight="1"  
  •             android:gravity="center_horizontal" >  
  •   
  •             <Button  
  •                 android:id="@+id/button_1"  
  •                 android:layout_width="80dip"  
  •                 android:layout_height="110dip"  
  •                 android:layout_marginTop="15dip"  
  •                 android:background="@drawable/default_cover" />  
  •         </LinearLayout>  
  •   
  •         <LinearLayout  
  •             android:layout_width="wrap_content"  
  •             android:layout_height="wrap_content"  
  •             android:layout_weight="1"  
  •             android:gravity="center_horizontal" >  
  •   
  •             <Button  
  •                 android:id="@+id/button_2"  
  •                 android:layout_width="80dip"  
  •                 android:layout_height="110dip"  
  •                 android:layout_marginTop="15dip"  
  •                 android:background="@drawable/default_cover" />  
  •         </LinearLayout>  
  •   
  •         <LinearLayout  
  •             android:layout_width="wrap_content"  
  •             android:layout_height="wrap_content"  
  •             android:layout_weight="1"  
  •             android:gravity="center_horizontal" >  
  •   
  •             <Button  
  •                 android:id="@+id/button_3"  
  •                 android:layout_width="80dip"  
  •                 android:layout_height="110dip"  
  •                 android:layout_marginTop="15dip"  
  •                 android:background="@drawable/default_cover" />  
  •         </LinearLayout>  
  •     </LinearLayout>  
  •   
  •     <ImageView  
  •         android:id="@+id/shelf_image_right"  
  •         android:layout_width="wrap_content"  
  •         android:layout_height="wrap_content"  
  •         android:layout_alignParentRight="true"  
  •         android:layout_centerVertical="true"  
  •         android:background="@drawable/bookshelf_layer_right" />  
  •   
  • </RelativeLayout>  

  •      最后是把item绑定到listview中:

     

     

    [html] view plaincopy
  • package cn.com.karl.reader;  
  •   
  • import android.app.Activity;  
  • import android.os.Bundle;  
  • import android.view.LayoutInflater;  
  • import android.view.View;  
  • import android.view.ViewGroup;  
  • import android.view.Window;  
  • import android.widget.BaseAdapter;  
  • import android.widget.ListView;  
  •   
  • public class IReaderActivity extends Activity {  
  •     /** Called when the activity is first created. */  
  •     private ListView shelf_list;  
  •     // 书架的列数  
  •     int[] size = new int[5];  
  •   
  •     @Override  
  •     public void onCreate(Bundle savedInstanceState) {  
  •         super.onCreate(savedInstanceState);  
  •         this.requestWindowFeature(Window.FEATURE_NO_TITLE);  
  •         setContentView(R.layout.main);  
  •   
  •         shelf_list = (ListView) findViewById(R.id.shelf_list);  
  •           
  •         ShelfAdapter adapter = new ShelfAdapter();  
  •         shelf_list.setAdapter(adapter);  
  •     }  
  •   
  •     public class ShelfAdapter extends BaseAdapter {  
  •           
  •   
  •         @Override  
  •         public int getCount() {  
  •             // TODO Auto-generated method stub  
  •             return size.length;  
  •         }  
  •   
  •         @Override  
  •         public Object getItem(int position) {  
  •             // TODO Auto-generated method stub  
  •             return size[position];  
  •         }  
  •   
  •         @Override  
  •         public long getItemId(int position) {  
  •             // TODO Auto-generated method stub  
  •             return position;  
  •         }  
  •   
  •         @Override  
  •         public View getView(int position, View convertView, ViewGroup parent) {  
  •             // TODO Auto-generated method stub  
  •             View layout = LayoutInflater.from(getApplicationContext()).inflate(  
  •                        R.layout.list_item, null);  
  •           
  •             return layout;  
  •         }  
  •   
  •     }  
  •   
  • }  
  •  

     

        每一本书对应的点击事件这里并没有做,相信大家可以实现,OK,下面看一下运行后效果:

     



        
    [2] 在map下默认显示注解,不用点击大头针就出来
        来源: 互联网  发布时间: 2014-02-18
    在地图上默认显示注解,不用点击大头针就出来

    - (void)viewDidAppear:(BOOL)animated
    {
        [super viewDidAppear:animated];
        [self addRestaurantAnnotation];
    }

     

     

     //下面一句话使得注解初始在上面显示。
        [self.gooleMapView selectAnnotation:annotation animated:YES];
        [annotationArray addObject:annotation];
        [annotation release];
       
        [_gooleMapView addAnnotations:annotationArray];


        
    [3] (通译) Backward Compatibility for Applications
        来源: 互联网  发布时间: 2014-02-18
    (翻译) Backward Compatibility for Applications

    原文来自Android SDK文档中的 docs/resources/articles/backward-compatibility.html

     

    目前有各种Android设备。 这些设备使用不同的Android版本, 有些运行最新的版本, 有些运行较老的版本。 作为开发者, 当考虑如何在应用中保持向后兼容——你是想让你的应用在所有Android设备上运行, 还是只能在最新的版本上运行? 有时有必要既享受新的API带来的便利(如果设备支持的话), 同时继续兼容老的设备。

     

    设置minSdkVersion

     

    如果应用的重要功能使用了新的API(原文if the use of new API is intergral to the application)——比如需要使用Android 1.5(API Level 3)中引入的新的API录制视频, 那么应当在应用的manifest中添加<android:minSdkVersion>,以保证这个应用不会被安装到更老的设备当中。 如果应用依赖于API Level 3中引入的新API, 应当指定minSdkVersion的值为3:

     

     

      <manifest>
       ...
       <uses-sdk android:minSdkVersion="3" />
       ...
      </manifest>

     

    但是, 如果你只是给应用增加了一个有用但非核心的特性, 比如在可使用实体键盘的情况下提供一个软键盘, 可以使用如下这种方式:既允许在新设备上使用这个特性, 同时不会在老的设备上引起错误。 

     

    使用反射

     

    假设想使用一个新的api, 比如android.os.Debug.dumpHprofData(String name)。 Debug类已经在android 1.0中存在, 但是方法是在Android 1.5(API Level 3)中新引入的。 如果你直接调用这个方法, 应用会在Android 1.1或更老的设备上崩溃。 

     

    最简单的办法是使用反射来调用这个方法。  这需要进行一次方法查询并将结果保存在一个Method对象上, 然后调用Method.invoke()方法, 最后解包该方法的返回值。 考虑下面这段代码:

     

     

    public class Reflect {
       private static Method mDebug_dumpHprofData;
    
       static {
           initCompatibility();
       };
    
       private static void initCompatibility() {
           try {
               mDebug_dumpHprofData = Debug.class.getMethod(
                       "dumpHprofData", new Class[] { String.class } );
               /* success, this is a newer device */
           } catch (NoSuchMethodException nsme) {
               /* failure, must be older device */
           }
       }
    
       private static void dumpHprofData(String fileName) throws IOException {
           try {
               mDebug_dumpHprofData.invoke(null, fileName);
           } catch (InvocationTargetException ite) {
               /* unpack original exception when possible */
               Throwable cause = ite.getCause();
               if (cause instanceof IOException) {
                   throw (IOException) cause;
               } else if (cause instanceof RuntimeException) {
                   throw (RuntimeException) cause;
               } else if (cause instanceof Error) {
                   throw (Error) cause;
               } else {
                   /* unexpected checked exception; wrap and re-throw */
                   throw new RuntimeException(ite);
               }
           } catch (IllegalAccessException ie) {
               System.err.println("unexpected " + ie);
           }
       }
    
       public void fiddle() {
           if (mDebug_dumpHprofData != null) {
               /* feature is supported */
               try {
                   dumpHprofData("/sdcard/dump.hprof");
               } catch (IOException ie) {
                   System.err.println("dump failed!");
               }
           } else {
               /* feature not supported, do something else */
               System.out.println("dump not supported");
           }
       }
    }
     

    这里使用一个静态块来调用 initCompatibility()方法, 该方法进行方法查询。 如果查询成功, 就使用跟原始语法相同的方式(argumnets, return value, checked exceptions)来调用这个私有方法。 返回值(如果有的话)和异常以类似于原始方式的形式被解包和返回。 fiddle()方法展示了应用的逻辑是如何来选择调用新的API,或者是根据新的API是否存在来干点别的事。 

     

    对每个想调用的新方法, 需要在当前类中添加一个额外的私有Method成员变量, 该成员变量对应的初始化方法, 以及调用包装器(原文: call wrapper)。 

     

    如果想调用的方法来自于先前未定义的类(注: 比如Android 1.0中没有, 但是Android 1.1新添加的类), 上述过程变得稍微有些复杂。 另外 , 调用Method.invode()比直接调用会慢很多。 可以使用一个包装类(Wrapper class)来部分减少这两个问题。

     

    使用包装类

     

    思路是添加一个新的包装类, 其作用是包装新添加的API(这些API可能来自已存在的类, 或是新添加的类)。 包装类中的每个方法仅仅是调用相应的目标方法并返回执行结果。 

     

    如果目标类和方法存在, 可以直接调用这些类并且有完全一致的行为, 当然, 额外的方法调用会带来少量的性能开销。 如果目标类或方法不存在, 包装类的初始化过程会失败, 应用就知道应当避免调用这些新方法。 考虑新加了如下类:

     

     

    public class NewClass {
       private static int mDiv = 1;
    
       private int mMult;
    
       public static void setGlobalDiv(int div) {
           mDiv = div;
       }
    
       public NewClass(int mult) {
           mMult = mult;
       }
    
       public int doStuff(int val) {
           return (val * mMult) / mDiv;
       }
    }

     

    然后为NewClass创建一个包装类

     

    class WrapNewClass {
       private NewClass mInstance;
    
       /* class initialization fails when this throws an exception */
       static {
           try {
               Class.forName("NewClass");
           } catch (Exception ex) {
               throw new RuntimeException(ex);
           }
       }
    
       /* calling here forces class initialization */
       public static void checkAvailable() {}
    
       public static void setGlobalDiv(int div) {
           NewClass.setGlobalDiv(div);
       }
    
       public WrapNewClass(int mult) {
           mInstance = new NewClass(mult);
       }
    
       public int doStuff(int val) {
           return mInstance.doStuff(val);
       }
    }

     

     

    这个包装类WrapNewClass包含原始类NewClass的各个方法(包括构造方法)的对应的包装方法, 另外还有一个静态初始化块用于检查NewClass类是否存在(注:这里有个小问题, 如果NewClass不存在,WrapNewClass的编译不是通不过吗?答案是, 一般采用新版本的SDK开发, 所以编译不成问题。 但是目标环境可能只支持低版本的SDK, 所以不存在NewClass的定义)。  如果 NewClass不存在, WrapNewClass的初始化过程失败, 注意应保证WrapNewClass(即包装类)不被随意使用。  checkAvailable()方法用于强制执行WrapNewClass的静态初始化块(注:这个初始化块会加载NewClass)。 我们这样使用:

     

     

    public class MyApp {
       private static boolean mNewClassAvailable;
    
       /* establish whether the "new" class is available to us */
       static {
           try {
               WrapNewClass.checkAvailable();
               mNewClassAvailable = true;
           } catch (Throwable t) {
               mNewClassAvailable = false;
           }
       }
    
       public void diddle() {
           if (mNewClassAvailable) {
               WrapNewClass.setGlobalDiv(4);
               WrapNewClass wnc = new WrapNewClass(40);
               System.out.println("newer API is available - " + wnc.doStuff(10));
           } else {
               System.out.println("newer API not available");
           }
       }
    }

     

     

    如果checkAvailable()方法调用成功, 我们就知道新的class在系统中存在;如果调用失败, 则不存在, 我们需要随之调整预期。 需要注意的是, 如果字节码校验器确信它不想接受这样一个类, 该类的某个成员变量的Class对象根本不存在(注:在 老版本的设备上可能出现这种情况, WrapNewClass的成员变量mInstance的Class对象不存在), 那么 checkAvailable()方法有可能在开始执行之前就失败。 上面代码的这种写法, 可以保证无论异常是来自字节码校验器还是Class.forName()调用, 执行结果都是一致的。

     

     当包装一个添加了新方法的已存在的类, 只需要将新添加的方法的包装方法添加到这个包装类;要使用原本存在的方法, 直接调用即可。 WrapNewClass的静态块会随着每个反射调用增大。(注:对每个可能的新class需要进行检查, 意味着多个Class.forName()调用)。  

     

    测试是王道

     

    必须在每个版本的Android平台上测试应用是否如期望的那样能够正常运行。 应用在不同的平台上(注:这里的不同平台应该指的是API发生了变化的平台, 而且应用刚好使用反射方法使用了这些API), 其行为应当不一致。 牢记: 如果没验证过, 它很可能不正确。 

     

    可以在老版本的模拟器上测试应用的向后兼容性。 Android SDK可以方便地使用不同的API Level创建"Android虚拟设备"。 创建好AVDs之后, 就可以使用新的和老版本来测试, 还能同时打开不同版本的模拟器来观察应用程序行为。 更多信息可以参考文档中的 Creating and Managing Virtual Devices一章, 或者运行emulator -help -virtual-device来查看帮助信息。 

     


        
    最新技术文章:
    ▪Android开发之登录验证实例教程
    ▪Android开发之注册登录方法示例
    ▪Android获取手机SIM卡运营商信息的方法
    ▪Android实现将已发送的短信写入短信数据库的...
    ▪Android发送短信功能代码
    ▪Android根据电话号码获得联系人头像实例代码
    ▪Android中GPS定位的用法实例
    ▪Android实现退出时关闭所有Activity的方法
    ▪Android实现文件的分割和组装
    ▪Android录音应用实例教程
    ▪Android双击返回键退出程序的实现方法
    ▪Android实现侦听电池状态显示、电量及充电动...
    ▪Android获取当前已连接的wifi信号强度的方法
    ▪Android实现动态显示或隐藏密码输入框的内容
    ▪根据USER-AGENT判断手机类型并跳转到相应的app...
    ▪Android Touch事件分发过程详解
    ▪Android中实现为TextView添加多个可点击的文本
    ▪Android程序设计之AIDL实例详解
    ▪Android显式启动与隐式启动Activity的区别介绍
    ▪Android按钮单击事件的四种常用写法总结
    ▪Android消息处理机制Looper和Handler详解
    ▪Android实现Back功能代码片段总结
    ▪Android实用的代码片段 常用代码总结
    ▪Android实现弹出键盘的方法
    ▪Android中通过view方式获取当前Activity的屏幕截...
    ▪Android提高之自定义Menu(TabMenu)实现方法
    ▪Android提高之多方向抽屉实现方法
    ▪Android提高之MediaPlayer播放网络音频的实现方法...
    ▪Android提高之MediaPlayer播放网络视频的实现方法...
    ▪Android提高之手游转电视游戏的模拟操控
     


    站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3