位置:首页 » 技术 » 浅谈 Android 编程思想和架构

浅谈 Android 编程思想和架构

日期:2016-03-11 阅读:0num
Advertisement

我主要是想讲一讲自己对于 接口、模块化、MVP 的一些心得。

有这么一个场景,两个不同的页面,包含了看起来一模一样的界面内容(或者称 frame),这种场景可能很常见,有时看到会说:“哈哈,我可以设计个复用!” 但是遇到一个问题是,这两个页面需要分别去请求不同的服务端 API,返回下来的数据结构也不一样(姑且不说去和服务端开发协商),这样就会导致具体的 view holder 或者适配器在绑定数据的时候无法复用,为何说无法复用或难以复用呢?举个例子,比如传进适配器的 list item 数据内容不一样,你总不能把 item 再拆了,分好几个 list 传进去吧?面向具体编程,适配器得到不同的具体的 items,得对 item 抽取内容绑定到 UI,难免要写很多重复的代码。

这时候我们可以采取面向抽象编程,既然不同的数据对应一样的 UI,如果它们都实现了一样的接口,这个接口的设计就看 UI 需要哪些内容,然后不同的 Item model 去实现这个接口提供数据即可,这时适配器只要持有这个接口类型的 item 即可,通俗地举个例子说,比如数据模型1和2都实现了 IPost 接口,那么适配器就只要持有 List<IPost> 数据即可,List<数据模型1> 和 List<数据模型2> 都可以视作“一样的鸭子”传递给这个适配器。这样把数据模型的数据层次抽取放到了数据模型本身实现,不仅不用写很多重复的分发代码,而且适配器本身都能复用了。

这就是抽象编程或者接口的好处,接口可以让不同的模型通过同样的方法提供内容,这样它们就可以一定程度上视为同类,就像外国有句话说的,如果一个动物走起来像鸭子,叫起来也像鸭子,我们就可以把它当作是鸭子。

另外,同样对于有相同可复用的 UI 这个场景,我们可以更进一步去做,即把 view holder 化为一个自定义 ViewGroup,或者包裹之。这样做的好处是,更多逻辑不同的地方也都能更好地去复用,而且对于 Adapter,你不需要再纠结 Item UI 的内容点击事件,是要回调到 Adapter 还是在 Adapter 内直径绑定数据响应。前者处理方式会导致 Adapter 得暴露很多接口,传递很多数据,经常要从数据集合中重新根据位置取绑定到数据,等等。后者,则会导致 Adapter 变得臃肿,处理过多不应该属于它的业务,而且同样存在着数据重复绑定问题。

这时候如果把 view holder 化为一个自定义 ViewGroup,那么交互数据的时候就可以进行UI数据绑定和响应数据绑定,而监听器建议是在初始化的时候就进行设置,避免 View 被复用的时候,重写设置数据的同时重复 new 出无谓的监听器对象。

其中,交互给 ViewGroup 这个对象的数据模型也是要使用接口模型,比如同样接收 IPost 接口对象作为数据,这样不同的类实现了同样的提供数据的接口,都能传入这个 ViewGroup 中供其使用。这里提供一个我的常用写法,使用 ViewGroup 关联一个 item 布局:

public class PostView extends LinearLayout implements View.OnClickListener {

    private TextView mSummary;
    private ImageView mAvatar;
    private TextView mUsername;
    private TextView mCreateAt;

    protected IPost mData;

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

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

    public PostView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        inflate(context, R.layout.view_post, this);
    }

    @Override protected void onFinishInflate() {
        super.onFinishInflate();
        mAvatar = (ImageView) findViewById(R.id.avatar);
        mUsername = (TextView) findViewById(R.id.username);
        mCreateAt = (TextView) findViewById(R.id.create_at);
        mSummary = (TextView) findViewById(R.id.summary);
        setOnClickListener(this);
    }

    public void setPost(IPost data) {
        mData = data;
        Glides.loadCircleImage(getContext(), data.getAvatar(), mAvatar);
        mUsername.setText(data.getUsername());
        mCreateAt.setText(data.getCreatedAtFromNow());
        mSummary.setText(data.getSummary());
    }

    @Override public void onClick(View v) {
        Intent intent = StreamActivity.newIntent(getContext(),
                mData.getAvatar(), mData.getUsername(), mData.getUserId(),
                mData.isCurrentUser());
        getContext().startActivity(intent);
    }
}

解释了接口的一些实际使用场景之后,我们接下来就很好谈 MVP 架构了,因为可能很多人会在使用 MVP 的时候产生困恼,为什么要搞那么多接口再实现,何不直接调用具体对象的方法?现在可能有点清楚了。

今年 Android 开发的技术趋势,我觉得一是 RxJava 会继续被更多人接受进而开始使用,二是谷歌花了不少心思的 Data Binding 很可能会迎来正式版,data binding 是实现 MVVM 架构的重要组成部分,介于它还不够完善而且目前还无法提供双向绑定,目前很多人包括俺都还只能停留在个人项目玩一玩的阶段,所以我也是笔记青睐于 MVP 架构。

MVP 逐渐流行起来了,必然是有一些好处,不然谁会去管这么一个新兴东西。首先就是它会更加易于测试,Android 平台默认的应用架构导致单元测试变得异常的困难,和 SDK 纠缠在一起的代码,使你无法改变要测试单元的预备状态,无法进行单元测试的准备步骤,而且很多情况,你无法获得测试内容的结果或者状态,也就无法完成断言内容。而使用 MVP 的好处就是能够更易于做测试,同时也能够有更好的复用性和松耦合性。

MVP 即 Model – Presenter – View,各部分之间的通讯,都是双向的,Presenter 持有 View 和 Model 的抽象引用,作为中间人,处理业务逻辑,Model 角色用于调取数据,而 View 则用于展现和控制 UI,它们都由中间人调度。抽象的好处前面说了,如果 M 或 V 有改变,只要换一个实现者就好了,对于 P,可以继续把它们当成提供不变的可调用方法对象。

对于包的结果,如果项目比较小,可以把不同的 Presenter 置于同一个 package 下,而如果页面数很多项目模块很多,则可以每一个模块分一套 MVP packages。

现在我们只要在 Activity 或 Fragment 中的生命周期简单做一些 UI 组件初始化等布置,然后一些业务逻辑工作就请求 Presenter 去完成,Presenter 内部持有 View 和 Model,Activity 是 View 的实现,于是 Presenter 调用 Model 去请求得到数据库或网络数据,完成之后再调用 View 的 UI 改变方法,或者把数据交给 View 去展现。如此,每个角色的代码都会变得很简洁、明确。而且,将业务逻辑放到 Presenter 中去,可以避免当 Activity 退出而后台线程仍然引用着 Activity,致使资源无法被系统回收从而引起内存泄露。

对于 Presenter 的设计,或者说具体应该把哪些内容放到 Presenter 中,是一个关键。Model 并不是必须有的,如果使用 RxJava 和 Retrofit,可以很清晰地获取数据库内容和网络数据,则可以把 Model 的工作纳入到 Presenter 中。如果带有 Model,则 Presenter 则要实现 Model 但回调,在回调中把数据传给 View 或响应。所以 Presenter 必须得有 View 但引用。

一个 Activity 可以有多个 Presenter,要用到什么业务就加入什么 Presenter,并且实现这个 Presenter 所需要的 View 接口即可,这就是简单的复用逻辑。

对于原本不是 MVP 的项目,结合 Android Studio 进行重构也很容易,AS 有个好用的功能快捷键是 option + enter,可以用来自动解决错误,利用它,我们可以很方便的把原本都写到 Activity 中的业务抽出,并且不用手动去创建各种接口中的方法和实现方法,步骤大概是这样的:

首先建一个业务的 Presenter 和一个 View 接口,Presenter 中加入 View 接口变量,并写个构造方法用于 View 初始化。而 View 接口,只要先放空即可。然后回到 Activity,implements View 接口,初始化 Presenter,并把自己交给 Presenter,找到原本业务逻辑的地方,把相关代码剪切,然后输入比如 mPresenter.loadData(); 这时候,Presenter 中并没有 loadData 这个方法,你只要按一下 option + enter 就可以出来自动在 Presenter 中创建这个方法的选项,然后自动创建了之后,再跳过去,粘贴刚才的代码,并且在回调的时候,调用 view.hideProgressBar() 方法,同样的,hideProgressBar 这个方法在 View 接口中并没有,于是 option + enter 自动在 View 接口中创建这个方法。这时候 Activity 就会报错,提示你必须实现 hideProgressBar 这个方法。这样就完成了整个循环驱动重构,是一条 step by step 很简单的套路。

相关文章
  • 浅谈 Android 编程思想和架构

    我主要是想讲一讲自己对于 接口.模块化.MVP 的一些心得. 有这么一个场景,两个不同的页面,包含了看起来一模一样的界面内容(或者称 frame),这种场景可能很常见,有时看到会说:"哈哈,我可以设计个复用!" 但是遇到一个问题是,这两个页面需要分别去请求不同的服务端 API,返回下来的数据结构也不一样(姑且不说去和服务端开发协商),这样就会导致具体的 view holder 或者适配器在绑定数据的时候无法复用,为何说无法复用或难以复用呢?举个例子,比如传进适配器的 list item

  • [Android 瓦匠] Android基础 之一:浅谈Android架构到HelloWorld案例的剖析 [Android 瓦匠] Android基础 之一:浅谈Android架构到HelloWorld案例的剖析

    [Android 泥水匠] Android基础 之一:浅谈Android架构到HelloWorld案例的剖析 作者:泥沙砖瓦浆木匠 网站:http://blog.csdn.net/jeffli1993 个人签名:打算起手不凡写出鸿篇巨作的人,往往坚持不了完成第一章节. 交流QQ群:[编程之美 365234583]http://qm.qq.com/cgi-bin/qm/qr?k=FhFAoaWwjP29_AonqzL0rpdQAjjqlHQQ 如果我的帮到了你,是否乐意捐助一下或请一杯啤酒也好呢?

  • 浅谈android中加载高清大图及图片压缩模式(二) 浅谈android中加载高清大图及图片压缩模式(二)

    浅谈android中加载高清大图及图片压缩方式(二) 这一讲就是本系列的第二篇,一起来聊下关于android中加载高清大图的问题,我们都知道如果我们直接加载原图的话,一个是非常慢,需要等待一定时间,如果没有在一定的时间内给用户响应的话,将会极大影响用户的体验.另一个是如果你的手机内存小的话,可能会直接崩溃.这也就是直接加载高清原图问题.遇到这些问题很容易想到的一点就是图片压缩,本篇文章也就是讲述图片压缩方式来实现加载高清大图的效果.但是现在问题就来了,通过上篇博客我们知道,手机的分辨率有很多,如

  • 浅谈Android中的MVC与MVP形式

    浅谈Android中的MVC与MVP模式 使用MVC或者MVP模式会增加很多的类,但是确可以让代码结构变得清晰,方便了后期维护拓展方便.把数据层跟视图层分离,处理事务的逻辑单独的放在一个类中,让Activity仅仅具有展示功能. 下面我们就MVC模式跟MVP模式进行分别讲解,总之来说各有利弊.在实际的开发中,我们根据实际情况进行取舍.个人认为MVP模式更简单一些,因为MVP模式中会把部分逻辑Activity中,但是这就造成了Activity的相对繁琐,没有实现完全的隔离.而我们采用的MVC模式则

  • 浅谈Internet产品的技术架构:(一)概述 浅谈Internet产品的技术架构:(一)概述

    浅谈互联网产品的技术架构:(一)概述 突然想起要写这个系列文章的起因是前阵子我内推了一大学同学,他面试完之后面试官对他扎实的基础.严谨的思维等优点非常满意,唯一可惜的是他之前没有过任何互联网行业的开发经验,最终难以达到该职位的要求. 我内推这位同学时对他是心里有数的,他在学校期间就很优秀,理论扎实动手能力也强,如果单论编程.算法.SQL.工具的使用等技能他是可以通过面试的.不过他毕业后一直做的是ERP系统开发,确实与互联网开发有出入. 我向他反馈完面试结果之后自己也在想:他所欠缺的互联网开发经验

  • 浅谈Android数据库CRUD操作的打包与实现(一) 浅谈Android数据库CRUD操作的打包与实现(一)

    浅谈Android数据库CRUD操作的封装与实现(一) Android系统内部集成了SQLite数据库,可是杯具的却没有Android系统可用的Hibernate. 想当初做JavaEE时有Hibernate在手的那个飘逸,我尝试用JavaEE的思路封装了一个类似的工具包.(感谢"编程浪子"在JavaEE上给我的帮助) 首先,晒晒我的包结构: 大家可以看到,我在项目中创建了两个SourceFolder.其中core文件夹下存放的都是通用代码,可以在其他项目中重复使用(当然最好是导出ja

  • 浅谈Android system_service 登记Service、APP获取并访问服务(PMS:PowerManagerService)为例

    浅谈Android system_service 注册Service.APP获取并访问服务(PMS:PowerManagerService)为例 一.Binder驱动程序.SMS守护进程的启动 { 1.binder-文件系统节点 { 1./sys/kernel/debug/bind1er/proc 每一个使用binder进程通信的进程,在此目录下都对应有一个文件,以进程ID命名 通过他们可以读取到各个进程的Binder线程池.binder实体对象.引用对象.内核缓冲区等信息. 2./sys/ke

  • 浅谈Android顶用接口完美实现回调的逻辑控制 浅谈Android顶用接口完美实现回调的逻辑控制

    浅谈Android中用接口完美实现回调的逻辑控制 让Android融入我的生活! 公司最近项目特别忙,难得抽时间出来写博客了,不过越忙,接触的东西越多,学的也就越多了! 本例要特别强调一下:只是对高内聚,低耦合思想的一点简单实现,重要思想,而不是代码,请广大读者朋友留意! 前段时间公司Android开发就我一个人,思维太封闭了,自己想个啥样,就写个啥样,现在呢,来了两个同事,项目由我和另外一个同事一起负责,有人交流,可以听听别人的理解,对我们的提高绝对是有益无害,我们也需要调整好自己的心态,能够

  • 浅谈android中的ListView之解决ScrollView跟ListView嵌套冲突(实际上一切都是浮云,闲的蛋疼)(一) 浅谈android中的ListView之解决ScrollView跟ListView嵌套冲突(实际上一切都是浮云,闲的蛋疼)(一)

    浅谈android中的ListView之解决ScrollView和ListView嵌套冲突(实际上一切都是浮云,闲的蛋疼)(一) 相信大家都已经可以熟练使用ListView和GridView,大神们估计都在使用RecyclerView了.如果还在使用ListView,你肯定有这样的一个深刻的感受,那就是在做一个APP的时候使用ListView和GridView很频繁,并且经常会遇到一个页面中除了有ListView或GridView可能还有一些其他的内容,但是可能内容很多,你第一时间就会想到让它整

  • 浅谈 Android L 的 Tint(着色) 浅谈 Android L 的 Tint(着色)

    浅谈 Android L 的 Tint(着色) Tint 是什么? Tint 翻译为着色. 着色,着什么色呢,和背景有关?当然是着背景的色.当我们开发 App 的时候,如果使用了 Theme.AppCompat 主题的时候,会发现 ActionBar 或者 Toolbar 及相应的控件的颜色会相应的变成我们在 Theme 中设置的 colorPrimary, colorPrimaryDark, colorAccent 这些颜色,这是为什么呢,这就全是 Tint 的功劳了! 这样做有什么好处呢?好

  • 浅谈Android五大格局(一)——LinearLayout、FrameLayout、AbsoulteLayout 浅谈Android五大格局(一)——LinearLayout、FrameLayout、AbsoulteLayout

    浅谈Android五大布局(一)--LinearLayout.FrameLayout.AbsoulteLayout Android的界面是有布局和组件协同完成的,布局好比是建筑里的框架,而组件则相当于建筑里的砖瓦.组件按照布局的要求依次排列,就组成了用户所看见的界面.Android的五大布局分别是LinearLayout(线性布局).FrameLayout(单帧布局).RelativeLayout(相对布局).AbsoluteLayout(绝对布局)和TableLayout(表格布局). Lin

  • Android日志之2012/02/16——浅谈Android重力感应

    Android日记之2012/02/16--浅谈Android重力感应 重力感应,也算是智能机和非智能机的区别之一了吧,Android设备中自然也能有这个功能. 在Android中,使用重力感应功能需要使用SensorEventListener,其中有两个方法, onSensorChanged和onAccuracyChanged,一般都是在onSensorChanged方法中做一些希望达到的效果处理(惭 愧,才刚接触这个重力感应,所以对这两个方法也不是很了解).重力感应是感应的一种方式,因此,我

  • 浅谈Android五大格局(二)——RelativeLayout和TableLayout 浅谈Android五大格局(二)——RelativeLayout和TableLayout

    浅谈Android五大布局(二)--RelativeLayout和TableLayout 在浅谈Android五大布局(一)中已经描述了LinearLayout(线性布局).FrameLayout(单帧布局)和AbsoulteLayout(绝对布局)三种布局结构,剩下的两种布局RelativeLayout(相对布局)和TableLayout(表格布局)相对之前布局结构稍显复杂一点,所以这里另起篇幅进行介绍. RelativeLayout: RelativeLayout按照各子元素之间的位置关系完

  • 浅谈MapReduce编程3

    浅谈MapReduce编程三 (3)下面实现一个自己的InputFormat,需要处理的数据为(时间:URL) public class TimeUrlTextInputInputFormat extends FileInputFormat<Text,URLWritable>{ public RecordReader<Text,URLWritable> getRecordReader( InputSplit input,JobConf job,Reporter reporter)t

  • 浅谈android的mount下令 浅谈android的mount下令

    浅谈android的mount命令 很多时候我们在android中删除不了文件,一般情况下可以用RE文件管理器来挂载可读写(别告诉我你不知道RE文件管理器)但是往往有时候在一些特殊的时候我们还是挂载不了怎么办? 就比如我的华为的U8500 很多时候我要删除一个东西的时候都不是很好删除,一直提示系统只读,用RE文件管理器也还是只读.难道这样就真的没招了吗?不是 我们可以手动挂载,手动挂载的命令是mount 在使用mount的时候你可以选择在手机终端里面输入命令也可以在电脑上面输入命令.只是在电脑上

  • 浅谈Android应用开发中一些概念的懂得

    浅谈Android应用开发中一些概念的理解 Android应用.Window应用和Web应用这3种应用是我们目前比较主流的应用程序开发类型,其实他们之间的设计思路有许多相同的地方,也有不同的地方.在各种技术之间相互借鉴,有助于我们理解Android应用开发模式的一些设计思路.下面我总结一下在Android应用开发中我对一些概念的理解. 1.开发Android应用程序时界面资源通过XML文件来定义,可以与Java源码分离,同时自动在R.java生成一个整形ID,在Java源码中可以通过这个ID来这

  • 浅谈Android onTouchEvent 与 onInterceptTouchEvent的差异详解

    浅谈Android onTouchEvent 与 onInterceptTouchEvent的区别详解 http://www.jb51.net/article/35800.htm

  • 浅谈Android系统开发中一些概念的了解

    浅谈Android系统开发中一些概念的理解 Android开发分为应用开发和系统开发,本文是<浅谈Android应用开发中一些概念的理解>的姊妹篇. Android系统基于Linux系统搭建,有其自己的特点,虽然系统开发技术通常只有ROM厂商或深度定制才需要,但对于应用开发人员来说,了解底层的一些实现,对于更好的应用Android应用框架来开发应用,是大有裨益的.下面总结一下我在Andriod系统开发学习过程中对一些概念的理解. 1.android系统启动过程:1)linux系统启动并初始化i

  • 浅谈MapReduce编程2

    浅谈MapReduce编程二 五.输入格式InputFormat 1. 实现了InputFormat接口的类负责输入文件的分片方式和读取. 2.常用的InputFormat子类 TextInputFormat :文件的每一行被记录,行的字节偏移量作为key,行的内容作为值 Key:LongWritable,value:Text KeyValueTextInputFormat:文件中的每一行被记录,每行中用一个分离器进行分离,分离 器前面的为Key,分离器后面的为value,分离器可以由key.v

  • 浅谈Android 卡通片,带你进入动画的世界 浅谈Android 卡通片,带你进入动画的世界

    浅谈Android 动画,带你进入动画的世界 背景: 其实我们Android 中大家都知道就那些东西,什么四大组件,activity,service,content provider,当然还有其东西,今天我也去总结了下,来说说Android 中动画这一模块,可能会有许多遗漏,希望大家见谅,多多给予补充. 一:老规矩了,先上效果图,没图没真相 二:Android Animation 内容的介绍 主要的内容包括以下 1.Animation ------------ 动画 2.tween Animat

最新文章
  • Issue - Gadget Lab - CSS Class 导致页面撑破

    @Livid http://www.v2ex.com/gadgetlab 内容区域 Div 的 .content 为960px,横向撑破了 .inner,去掉就okey了. --cut--

  • 尝试走出沙漠【优秀作文】

    高三励志文章_尝试走出沙漠 有一个故事,说的是在西撒哈拉沙漠中有一个小村庄比赛尔,它在没有被发现之前,还是一块贫脊之地,那里的人没有一个走出过大漠.据说不是他们不愿离开那儿,而是他们尝试过很多次都没能走出去.当一个现代的西方人到了那儿,听说了这件事后,他决心做一次试验.他从比赛尔村向北走,结果三天半就走出来了. 经过此事,他终于明白比赛尔人之所以走不出大漠,是因为他们根本就不认识北斗星.因此,他告诉当地的一位青年,要想走出大漠.只要白天休息,夜晚朝着北面那颗星走,就能走出大漠.那个青年照着他的话

  • 水中瑜伽的好处 水中瑜伽的好处

    瑜伽一直都是美眉减肥的首选运动,那么如今是夏季了,在一个密封的房间练习瑜伽不如到水中练瑜伽更爽快,而且水中练瑜伽让你瘦身效果更好,下面就一起来了解下水中瑜伽的好处. 一.费力更大--人在水中活动的受阻感是空气中的800多倍.如果动作速度相同,完成同样的一组动作,水中与陆地相比至少要多用6倍以上的力量.所以,水中运动会取得事半功倍的效果. 二.呵护肌肤--由于水中运动相对出汗较少,减少了陆上训练后汗水中的盐分对皮肤的刺激.水流.波浪的摩擦和拍打具有特殊的按摩作用,可有效避免并减少肌肤的松弛和老化,

  • 梯子网解散 网络红娘跨界在线教育的得与失

    本周五,中国最大的电商平台阿里将在万里之外的美国开辟其征服国际资本市场的新旅程.据媒体报道,由于急于入股阿里的投资者太多,阿里的招股价有望从原先预计的每股60-66美元涨至66-68美元,按照这一涨幅,阿里的囊中又将多收入几亿美元,阿里成为史上最大的IPO已无悬念,我们所期待的,只是想看看阿里本周五开盘后股价能够比开盘价涨多少. 英语教师出身的龚海燕也在跨界投资在线教育屡屡受挫之后决定解散其投资的在线教育网站梯子网. "转了一圈回到原点,决定聚焦91外教,希望以后为大家提供更好的在线口语教学服务

  • 百度地图,“我与世界”的杀手级产品

    骂街谁都会,破坏是条狗都能搞,难的是有没有建设性意见.对此我深表赞同.变化需要一个过程,就像3年前我对it技术一窍不通,但现在却在看安卓应用开发,百度的变化也需要一个过程.经历"门户大战","搜索为王"时代后,互联网入口会演变成怎样格局难以预测,但互联网数据的越加规整以及移动互联的崛起已经是难以避免.回应朋友的讽刺,我们就一起来发现百度的更多产品以及他们可能的走势,现在先从百度地图开始. 百度地图的使用经历 百度地图,是继百度搜索.百度音乐.百度新闻之后我最常用的一

  • 《LOL》新英雄海兽祭司俄洛伊介绍 《LOL》新英雄海兽祭司俄洛伊介绍

    英雄联盟第128位英雄海兽祭司俄洛伊已经在美服测试服曝光,新英雄俄洛伊的英文名字是Illaoi,而且她是一位女性英雄哦,那么俄洛伊的技能是什么样子的,下面一起看看新英雄俄洛伊属性.技能以及视频预览吧. >>新英雄俄洛伊天赋符文攻略 基础属性: 伤害:60(+5) 生命值:585.6(+95) 法力值:300(+40) 移速:340 护甲:26(+3.8) 魔抗:32.1(+1.25) 每5秒生命回复:9.5(+0.8) 每5秒法力回复:7.5(+0.75) 攻击距离:125 俄洛伊技能介绍:(

  • 哪位帅哥教我做css的导航条?

    哪位帅哥教我做css的导航条? 最佳答案 这是一个完整的导航条代码,我给你加了注释,你可以自己灵活使用. 至于那三个图片,可以根据CSS中的尺寸来自己制作,2px宽就可以了.hover颜色一般要比link和visted的颜色亮一些.如果做不出来,可以到我博客找我的联系方式,要素材. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD

  • 多年以后,我们很难是朋友,往往是路人

    过年的时候,我总是被问到一个问题,要不要去参加同学聚会? 有个同学就问我:"大叔,同学会有必要勉强自己去么?因为去了还是跟自己比较好的同学一起玩而已吧.我从高中毕业后就没去过同学会了,觉得干脆找要好的同学去玩更好."但是她又觉得"看到同学微信留言上说'不珍惜的人就算了吧',心里觉得有点对不住他们,还有一年就毕业了,觉得起码去聚聚吧,可没有人强迫我的话,我还是迈不开脚步,好纠结好矛盾呢--" 估计很多人都有这种纠结吧. 有这种聚会但不想去的同学,我想可能是如下原因:

  • WINCE6.0上 GDI+ WINCE6.0上 GDI+

    WINCE6.0上 GDI+ 求助 我们现在需要在产品UI上做一些特效,需要用到GDI+方面的东西,但是找不到ce6.0上可以用的基于ARM的gdiplus.dll. 不知道各位大神有没有做过的.给点提示.或有没有相关库的发下给我,感激,急切![email protected] 分享到: ------解决方案-------------------- wince不支持gdi+! ------解决方案-------------------- 路过帮前辈顶一下 前辈找到了 给大家分享下 ------解

  • (Visual C++)游戏开发笔记之一——API函数、DirectX的关键系统

    在从第一节开始看这个笔记系列的话,大家会发现,一上来就开始讲DirectX相关的内容,但是写了几节之后,又开始讲GDI了. 这是因为我写完前几节后,发觉直接讲DirectX有些生硬.最后我想了一下,应该先梳理完GDI相关的重点知识,再来讲DirectX,毕 竟游戏编程里面windows API是基础.所以先讲windows API,再来讲DirectX,这样会自然得多. ----浅墨于2012年3月26日注 作为visual C++,DirectX入门的第一讲,概念性东西比较多. 1.Direc

热门推荐