【0096】【项目实战】-【开源中国】-【02】
1.BaseListFragment的封装分析-重新听
【带有listView的加载数据的抽取】每个界面都有listView的加载数据和下拉刷新的加载的效果




2.SwipeRefreshLayout的使用
.


【源码】


【设置一个右侧的边框】


【对比说明】Drawer只可以覆盖半个,必须留有边框;
Sliding pane layout 可以完全覆盖整个Activity;


【SwipRefreshLayout】效果

【源码】/Support4Demos-19/src/com/example/android/supportv4/widget/SwipeRefreshLayoutActivity.java
1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.example.android.supportv4.widget; 18 19 import android.app.Activity; 20 import android.os.Bundle; 21 import android.os.Handler; 22 import android.support.v4.widget.SwipeRefreshLayout; 23 import android.view.Menu; 24 import android.view.MenuInflater; 25 import android.view.MenuItem; 26 import android.view.MotionEvent; 27 import android.view.View; 28 import android.view.View.OnClickListener; 29 import android.widget.ArrayAdapter; 30 import android.widget.Button; 31 import android.widget.ListView; 32 import android.widget.Toast; 33 34 import com.example.android.supportv4.R; 35 import com.example.android.supportv4.Shakespeare; 36 37 import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener; 38 39 /** 40 * Example of using the SwipeRefreshLayout. 41 */ 42 public class SwipeRefreshLayoutActivity extends Activity implements OnRefreshListener { //【1】继承与Activity 43 public static final String[] TITLES = 44 { 45 "Henry IV (1)", 46 "Henry V", 47 "Henry VIII", 48 "Richard II", 49 "Richard III", 50 "Merchant of Venice", 51 "Othello", 52 "King Lear", 53 "Henry IV (1)", 54 "Henry V", 55 "Henry VIII", 56 "Richard II", 57 "Richard III", 58 "Merchant of Venice", 59 "Othello", 60 "King Lear", 61 "Henry IV (1)", 62 "Henry V", 63 "Henry VIII", 64 "Richard II", 65 "Richard III", 66 "Merchant of Venice", 67 "Othello", 68 "King Lear", 69 "Henry IV (1)", 70 "Henry V", 71 "Henry VIII", 72 "Richard II", 73 "Richard III", 74 "Merchant of Venice", 75 "Othello", 76 "King Lear" 77 }; 78 // Try a SUPER quick refresh to make sure we don't get extra refreshes 79 // while the user's finger is still down. 80 private static final boolean SUPER_QUICK_REFRESH = false; 81 private View mContent; 82 private SwipeRefreshLayout mSwipeRefreshWidget; 83 private ListView mList; 84 private Handler mHandler = new Handler(); 85 private final Runnable mRefreshDone = new Runnable() { 86 87 @Override 88 public void run() { 89 mSwipeRefreshWidget.setRefreshing(false); //【8】结束刷新 90 } 91 92 }; 93 @Override 94 public void onCreate(Bundle bundle) { 95 super.onCreate(bundle); 96 setContentView(R.layout.swipe_refresh_widget_sample); 97 mSwipeRefreshWidget = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_widget); 98 mSwipeRefreshWidget.setColorScheme(R.color.color1, R.color.color2, R.color.color3, //【2】设置四个颜色条 99 R.color.color4); 100 mList = (ListView) findViewById(R.id.content); 101 ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this, 102 android.R.layout.simple_list_item_1, android.R.id.text1, TITLES); //【3】设置适配器adpater; 103 mList.setAdapter(arrayAdapter); //设置适配器 104 mSwipeRefreshWidget.setOnRefreshListener(this); //【4】设置监听事件,在42行的时候SwipeRefreshLayoutActivity实现了OnRefreshListener 105 } 106 107 @Override 108 public void onRefresh() { //【5】下拉刷新的时候调用此方法 109 refresh();//【6】调用了136行、137行的方法; 110 } 111 112 113 @Override 114 public boolean onCreateOptionsMenu(Menu menu) { 115 MenuInflater inflater = getMenuInflater(); 116 inflater.inflate(R.menu.swipe_refresh_menu, menu); 117 return true; 118 } 119 120 /** 121 * Click handler for the menu item to force a refresh. 122 */ 123 @Override 124 public boolean onOptionsItemSelected(MenuItem item) { 125 final int id = item.getItemId(); 126 switch(id) { 127 case R.id.force_refresh: 128 mSwipeRefreshWidget.setRefreshing(true); 129 refresh(); 130 return true; 131 } 132 return false; 133 } 134 135 private void refresh() { 136 mHandler.removeCallbacks(mRefreshDone); //移除之前的任务 137 mHandler.postDelayed(mRefreshDone, 1000);// 【7】延时执行85行的方法 138 } 139 }
【布局】
【说明】android.support.v4.widget.SwipeRefreshLayout中可以包括任何的主界面的控件,此处包裹的是listView;包裹谁谁就可以下拉刷新;
1 <?xml version="1.0" encoding="utf-8"?> 2 <!-- Copyright (C) 2013 The Android Open Source Project 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 --> 16 17 <android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android" 18 android:id="@+id/swipe_refresh_widget" 19 android:layout_width="match_parent" 20 android:layout_height="match_parent"> 21 <!-- some full screen pullable view that will be the offsetable content --> 22 <ListView 23 android:layout_width="match_parent" 24 android:layout_height="match_parent" 25 android:id="@+id/content"/> 26 </android.support.v4.widget.SwipeRefreshLayout>
【5.0之后的效果】变为了圆圈;

3.android动画总结
1 四.android动画总结 2 1.补间动画:TranslationAnimation,RotationAnimation,AlphaAnimation,ScaleAnimation; 3 缺点:早期的补间动画绘制出来的效果其实并没有真正改变View的属性,只是系统临时绘制 4 出来的效果; 5 2.属性动画:3.0之后谷歌提出,属性动画就是用新增的属性(如translationX,translationY, 6 scaleX,scaleY,rotation,rotationX等等)用来记录view的改变的值;这样就允许 7 动画能保存并持续进行; 8 3.与属性动画相关的类和方法: 9 a.更改view属性的方法: 10 view.setTranslationX(x);//3.0之后的方法 11 ViewHelper.setTranslationX(view,x);//NineOldAndroid动画类库中的类 12 13 b.ValueAnimatior和ObjectAnimatior; 14 ObjectAnimatior允许你直接更改View的新属性; 15 ValueAnimatior只是帮你定义和执行动画流程,并没有实现任何的动画逻辑,需要 16 你添加动画更新的监听,在执行过程中进行自定义的动画逻辑; 17 18 c.ViewPropertyAnimator:一般用NineOldAndroid中的类,它简化了ObjectAnimator 19 类的操作,然后直接运行我们执行更改View属性的动画; 20 ViewPropertyAnimator.animate(view).translationX(10).setDuration(300).start();
3.1.缩放动画的不同实现
【布局】


【ObjectAnimator变宽】此类只能使用的3.0之上,不兼容低版本的;


【ViewPropertyAnimator的实现】

[效果]具有,缩放动画,最后弹性显示

3.2 平移动画


【差值效果】像球弹起一样


【差值效果】左右震动

[效果]左右抖动,类似的使用场景是输入密码错误的文本框;

【文本框从屏幕上面隐藏的状态滑动到屏幕的指定的位置】



【修改优化】


【说明】在属性动画执行的时候,控件本身的left、top值是没有改变的,此属性的坐标系参考的是父类的坐标系;、
但是,属性动画的坐标的transX和transX移动的时候参考的坐标系是自身的坐标系,发生了改变;

【打印结果】看出在translationBy之后的top值仍然是顶在了Activity的顶部,没有改变;

4.网络框架的封装
【说明】在项目中的封装,分为原始的封装---系统层的封装---业务的封装;在实际的项目中都会封装到最后的业务层;

4.1 方式2的封装-调用
【方式2的封装-调用】


【方式2的封装-调用】


4.2 方式3的封装

1 package com.itheima.oschina.api.remote; 2 3 import java.io.File; 4 import java.io.FileNotFoundException; 5 6 import org.kymjs.kjframe.utils.KJLoger; 7 8 import android.text.TextUtils; 9 10 import com.itheima.oschina.AppContext; 11 import com.itheima.oschina.api.ApiHttpClient; 12 import com.itheima.oschina.bean.BlogList; 13 import com.itheima.oschina.bean.Tweet; 14 import com.itheima.oschina.bean.TweetsList; 15 import com.itheima.oschina.util.TLog; 16 import com.loopj.android.http.AsyncHttpResponseHandler; 17 import com.loopj.android.http.RequestParams; 18 19 public class OSChinaApi { //再次封装 20 21 /** 22 * 登陆 23 * 24 * @param username 25 * @param password 26 * @param handler 27 */ 28 public static void login(String username, String password, 29 AsyncHttpResponseHandler handler) { 30 RequestParams params = new RequestParams(); 31 params.put("username", username); 32 params.put("pwd", password); 33 params.put("keep_login", 1); 34 String loginurl = "action/api/login_validate"; 35 ApiHttpClient.post(loginurl, params, handler); 36 } 37 38 /** 39 * 获取新闻列表 40 * 41 * @param catalog 42 * 类别 (1,2,3) 43 * @param page 44 * 第几页 45 * @param handler 46 */ 47 public static void getNewsList(int catalog, int page, 48 AsyncHttpResponseHandler handler) { 49 RequestParams params = new RequestParams(); 50 // params.put("catalog", catalog); 51 // params.put("pageIndex", page); 52 // params.put("pageSize", AppContext.PAGE_SIZE); 53 // if (catalog == NewsList.CATALOG_WEEK) { 54 // params.put("show", "week"); 55 // } else if (catalog == NewsList.CATALOG_MONTH) { 56 // params.put("show", "month"); 57 // } 58 // 59 // ApiHttpClient.get("action/api/news_list", params, handler); 60 61 TLog.log("getNewsList: catalog: " + catalog + " page: " + page); 62 String path = ""; 63 switch (catalog) { //根据类别的信息进行path的拼接 64 case 1: 65 path = "oschina/list/news/page"+page+".xml"; 66 break; 67 case 4: 68 path = "oschina/list/hotspot/page"+page+".xml"; 69 break; 70 } 71 72 ApiHttpClient.getLocal(path, params, handler); //调用第二种方式中的封装; 73 } 74 75 public static void getBlogList(String type, int pageIndex, 76 AsyncHttpResponseHandler handler) { 77 RequestParams params = new RequestParams(); 78 // params.put("type", type); 79 // params.put("pageIndex", pageIndex); 80 // params.put("pageSize", AppContext.PAGE_SIZE); 81 // ApiHttpClient.get("action/api/blog_list", params, handler); 82 83 String path = ""; 84 if(BlogList.CATALOG_LATEST.equals(type)){ 85 path = "oschina/list/blog/page"+pageIndex+".xml"; 86 }else if (BlogList.CATALOG_RECOMMEND.equals(type)) { 87 path = "oschina/list/recommend/page"+pageIndex+".xml"; 88 } 89 90 ApiHttpClient.getLocal(path, params, handler); 91 }
4.3. 手机客户端信息的传递和获取


4.4.网络二次封装




4.5【封装的好处】
【好处】替换第三方的框架,可以直接封装,到时候直接替换库就可以
【替换第三方开发的库】只需要修改方法的参数和定义的类就可以


5.自定义对话框
5.1 效果及分析
【效果】可以使用popWindow(剩余部分的黑色透明部分显示的时候没有渐变的效果,需要增加动画)、对话框、Acvitity实现(消耗内存大);
【此处使用的对话框】

【说明】此处的对话框,与之前遇到的对话框不一样;
【位置】之前的弹出位置在屏幕中间;现在在底部;
【占据屏幕比例】之前在四周围都有距离,现在的占满屏幕的下半部分;

5.2 自定义对话框的构造

【继承与Dialog】

【完成动画的定义】


【进入动画】

【退出动画】


【初始化View对象】加载布局


[布局源码]
1 <?xml version="1.0" encoding="utf-8"?> 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:id="@+id/set_pop" 4 android:layout_width="match_parent" 5 android:layout_height="wrap_content" > 6 7 <LinearLayout 8 android:id="@+id/ll_option_container" 9 android:layout_width="match_parent" 10 android:layout_height="wrap_content" 11 android:orientation="vertical" > 12 13 <LinearLayout 14 android:layout_width="match_parent" 15 android:layout_height="wrap_content" 16 android:orientation="horizontal" > 17 18 <LinearLayout 19 android:id="@+id/ly_quick_option_text" 20 style="@style/quick_option_item" > 21 22 <ImageView 23 android:layout_width="wrap_content" 24 android:layout_height="wrap_content" 25 android:src="@drawable/quickoption_icon_text_selector" /> 26 27 <TextView 28 style="@style/quick_option_item_text" 29 android:text="@string/quick_option_text" /> 30 </LinearLayout> 31 32 <LinearLayout 33 android:id="@+id/ly_quick_option_album" 34 style="@style/quick_option_item" > 35 36 <ImageView 37 android:layout_width="wrap_content" 38 android:layout_height="wrap_content" 39 android:src="@drawable/quickoption_icon_album_selector" /> 40 41 <TextView 42 style="@style/quick_option_item_text" 43 android:text="@string/quick_option_album" /> 44 </LinearLayout> 45 46 <LinearLayout 47 android:id="@+id/ly_quick_option_photo" 48 style="@style/quick_option_item" > 49 50 <ImageView 51 android:layout_width="wrap_content" 52 android:layout_height="wrap_content" 53 android:background="@null" 54 android:src="@drawable/quickoption_icon_photo_selector" /> 55 56 <TextView 57 style="@style/quick_option_item_text" 58 android:text="@string/quick_option_photo" /> 59 </LinearLayout> 60 </LinearLayout> 61 62 </LinearLayout> 63 64 <LinearLayout 65 android:id="@+id/ll_foot" 66 android:layout_width="match_parent" 67 android:layout_height="wrap_content" 68 android:layout_below="@id/ll_option_container" 69 android:background="@color/list_item_background_normal" 70 android:gravity="center" 71 android:padding="10dip" 72 android:visibility="visible" > 73 74 <ImageView 75 android:id="@+id/iv_close" 76 android:layout_width="35dp" 77 android:layout_height="35dp" 78 android:contentDescription="@null" 79 android:focusable="false" 80 android:src="@drawable/btn_quickoption_route" /> 81 </LinearLayout> 82 83 </RelativeLayout>
【增加点击按钮的旋转动画】



【点击界面的其他部分消失】点击除了按钮(相册、拍照、文字按钮)之外的任何地方都可以使得对话框消失;

【但是点击按钮之后的子控件可以显示效果】因为按钮是对话框的子控件,子控件将事件进行了拦截;

【设置布局】

【设置对话框在底部】默认是在中间;


【设置对话框和当前屏幕的宽度一致】

6.自定义ActionBar的内容
6.1 demo
【自定义ActionBar】在详情页中存在一个自定义的ActionBar,需要自定义箭头--竖线--文字;


【自定义一个ActionBar】


【设定充满整个ActonBar的标题栏】


6.2 项目中的使用

【设置标题栏的占据整个的宽度】设置参数

7.WebView高级处理
7.1 查找某个正在运行的Activity的方法
【直接查看日志信息】

7.2 子类的初始化
【说明】Activity只是一个容器,fragment是其中要填充的内容;


【新闻详情页的中的WebView】

【布局中的WebView】

【WebView的初始化】增加一个WebViewClient,并且可以增加超链接的跳转;

7.3 父类的逻辑
【逻辑分析】在子类中仅仅执行了init初始化的任务,其他的逻辑是在父类中执行的;
7.3.1【请求数据】


【子类方法中传递的关键参数】
【mHandler】核心是更新UI的操作;

【更新UI】executOnLoadDataSuccess()方法

7.3.2 [子类复写该方法]核心代码:fillWebViewBody之图片的加载

【获取的html的中body信息】


【WebView对html中的图片的显示】其中存在java代码与js代码的交互,比较麻烦;

【参考文档】java代码和js代码的交互
Android 中可以通过webview来实现和js的交互,在程序中调用js代码,只需要将webview控件的支持js的属性设置为true
Android(Java)与 JavaScript(HTML)交互有四种情况:
1) Android(Java)调用HTML中js代码
2) Android(Java)调用HTML中js代码(带参数)
3) HTML中js调用Android(Java)代码
4) HTML中js调用Android(Java)代码(带参数)
下面示例总结这四种情况,直接上干货:
1) Android(Java)


js(HTML)



4) 代码解析:
(1) 允许Android执行js脚本设置
Android(Java)与js(HTML)交互的接口函数是: mWebView.addJavascriptInterface(getHtmlObject(), "jsObj"); // jsObj 为桥连对象
Android容许执行js脚本需要设置: webSettings.setJavaScriptEnabled(true);
(2) js(HTML)访问Android(Java)代码
js(HTML)访问Android(Java)端代码是通过jsObj对象实现的,调用jsObj对象中的函数,如: window.jsObj.HtmlcallJava()
(3) Android(Java)访问js(HTML)代码
Android(Java)访问js(HTML)端代码是通过loadUrl函数实现的,访问格式如:mWebView.loadUrl("javascript: showFromHtml()");
说明:
1)
Android访问url网址,需在AndroidManifest.xml文件,配置容许访问网络的权限:
<uses-permission android:name="android.permission.INTERNET" />
2) Android(Java)调用js(HTML)时,使用的mWebView.loadUrl("javascript: showFromHtml()");函数需在UI线程运行,因为mWebView为UI控件

7.3.3继续分析fillWebViewBody
【网页文本样式的替换】为了使得大网页的界面可以适配手机屏幕的显示;


浙公网安备 33010602011771号