打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
一个小时打造新闻app

前言

作为一个新手,学完基础总想做点什么东西出来。于是我试着去模仿那些优秀的开源作品。
模仿作品:LookLook开源项目
经过一些波折和学习,写下模仿过程。

一个小时打造新闻app

实际上我花了大概三天才弄懂所有的东西,不过有了经验确实可以在一个小时里完成。

使用框架:

rxjava和retrofit以及一个开源扩展的recyclerview和注解框架butterknife
集体依赖如下:

dependencies {    compile fileTree(include: ['*.jar'], dir: 'libs')    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {        exclude group: 'com.android.support', module: 'support-annotations'    })    compile 'com.android.support:appcompat-v7:24.2.1'    compile 'com.android.support:design:24.2.1'    testCompile 'junit:junit:4.12'    //依赖注解    //依赖添加    compile 'com.jakewharton:butterknife:8.4.0'    apt 'com.jakewharton:butterknife-compiler:8.4.0'    compile 'com.google.code.gson:gson:2.7'    //高级的recyclerview    compile 'com.jude:easyrecyclerview:4.2.3'    compile 'com.android.support:recyclerview-v7:24.2.0'    //rxjava    compile 'com.squareup.retrofit2:retrofit-converters:2.1.0'    compile 'com.squareup.retrofit2:converter-gson:2.1.0'    compile 'io.reactivex:rxandroid:1.2.1'    compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'    compile 'com.squareup.retrofit2:retrofit:2.1.0'    compile 'com.squareup.retrofit2:converter-scalars:2.1.0'    compile 'com.github.bumptech.glide:glide:3.7.0'}

开始制作app

界面制作:

新建项目,选择模板---->调整模板


QQ截图20161025085115.png

菜单调整

可以看到有menu里面两个文件
一个是主菜单,显示在Toobar上面
另一个是抽屉的菜单,按需修改即可。
activity_main_drawer.xml

<?xml version="1.0" encoding="utf-8"?><menu xmlns:android="http://schemas.android.com/apk/res/android">    <group android:checkableBehavior="single">        <item            android:id="@+id/nav_camera"            android:icon="@drawable/ic_menu_slideshow"            android:title="新闻精选" />        <item            android:id="@+id/nav_gallery"            android:icon="@drawable/ic_face_black_24dp"            android:title="轻松一刻" />        <item            android:id="@+id/nav_slideshow"            android:icon="@drawable/ic_menu_gallery"            android:title="每日美图" />        <item            android:id="@+id/nav_manage"            android:icon="@drawable/ic_menu_manage"            android:title="应用推荐" />    </group>    <item android:title="其他">        <menu>            <item                android:id="@+id/nav_share"                android:icon="@drawable/ic_menu_share"                android:title="软件分享" />            <item                android:id="@+id/nav_send"                android:icon="@drawable/ic_menu_send"                android:title="软件关于" />        </menu>    </item></menu>

抽屉除了menu还有上面一部分,可以设置头像和签名。
nav_header_main.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-auto"    android:layout_width="match_parent"    android:layout_height="@dimen/nav_header_height"    android:background="@drawable/side_nav_bar"    android:gravity="bottom"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:theme="@style/ThemeOverlay.AppCompat.Dark"    android:orientation="vertical">    <ImageView        android:layout_gravity="center"        android:id="@+id/imageView"        android:layout_width="100dp"        android:layout_height="100dp"        app:srcCompat="@drawable/ic_app_icon" />    <TextView        android:gravity="center"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="一日之计在于晨,一年之计在于春。"        android:textAppearance="@style/TextAppearance.AppCompat.Body1" />    <TextView        android:gravity="center"        android:id="@+id/textView"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="1458476478@qq.com" /></LinearLayout>

主界面大概这就可以了,剩下的就是要动态添加fragement到FragLayout里面去。

数据获取

首先新建fragment_news,布局文件只需要一个EasyRecyclerView即可

添加依赖

//高级的recyclerview    compile 'com.jude:easyrecyclerview:4.2.3'    compile 'com.android.support:recyclerview-v7:24.2.0'
<?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-auto"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical">    <com.jude.easyrecyclerview.EasyRecyclerView        android:id="@+id/recyclerView"        android:layout_width="match_parent"        android:layout_height="match_parent"        app:recyclerClipToPadding="true"        app:recyclerPadding="8dp"        app:recyclerPaddingBottom="8dp"        app:recyclerPaddingLeft="8dp"        app:recyclerPaddingRight="8dp"        app:recyclerPaddingTop="8dp"        app:scrollbarStyle="insideOverlay"        app:scrollbars="none" /></LinearLayout>

使用rxjava和retrofit获取json数据

我的数据来自天性数据,只需要注册即可获得APIKEY。
数据请求核心代码:

创建retrofit的请求接口

public interface ApiService{    @GET("social/")    Observable <NewsGson> getNewsData(@Query("key")String key,@Query("num") String num,@Query("page") int page);

注意返回的是Gson数据而且设置为"被观察者"

数据获取函数:

private void getData() {        Log.d("page", page + "");        Retrofit retrofit = new Retrofit.Builder()                .baseUrl("http://api.tianapi.com/")                //String                .addConverterFactory(ScalarsConverterFactory.create())                .addConverterFactory(GsonConverterFactory.create())//添加 json 转换器                //    compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())//添加 RxJava 适配器                .build();        ApiService apiManager = retrofit.create(ApiService.class);//这里采用的是Java的动态代理模式        apiManager.getNewsData("你的APIKREY", "10", page)                .subscribeOn(Schedulers.io())                .map(new Func1<NewsGson, List<News>>() {                    @Override                    public List<News> call(NewsGson newsgson) { //                        List<News> newsList = new ArrayList<News>();                        for (NewsGson.NewslistBean newslistBean : newsgson.getNewslist()) {                            News new1 = new News();                            new1.setTitle(newslistBean.getTitle());                            new1.setCtime(newslistBean.getCtime());                            new1.setDescription(newslistBean.getDescription());                            new1.setPicUrl(newslistBean.getPicUrl());                            new1.setUrl(newslistBean.getUrl());                            newsList.add(new1);                        }                        return newsList; // 返回类型                    }                })                .observeOn(AndroidSchedulers.mainThread())                .subscribe(new Subscriber<List<News>>() {                    @Override                    public void onNext(List<News> newsList) {                        adapter.addAll(newsList);                    }                    @Override                    public void onCompleted() {                    }                    @Override                    public void onError(Throwable e) {                        Toast.makeText(getContext(),                                "网络连接失败", Toast.LENGTH_LONG).show();                    }                });        page = page + 1;    }
  1. 使用retrofit 发起网络请求
  2. 数据通过rxjava提交先在io线程里,返回到主线程
  3. 中间设置map 转换 把得到的Gson类转化为所需的News类(可以省略这一步)
  4. subscribe的onNext里处理返回的最终数据。

关于建立Gson类

Gson是谷歌的Json处理包,添加依赖。
compile 'com.google.code.gson:gson:2.7'
配合插件:GsonFormat可以快速通过json数据建立对应类。


my.gif

数据绑定到recyview

由于我们使用的是被扩展的recyview,所以用起来很方便。
具体使用去作者的githuaEasyRecyclerView

  1. Adapter
    继承recycle的adapter,主要返回自己的ViewHolder

    public class NewsAdapter extends RecyclerArrayAdapter<News> { public NewsAdapter(Context context) {     super(context); } @Override public BaseViewHolder OnCreateViewHolder(ViewGroup parent, int viewType) {     return new NewsViewHolder(parent); }}
  2. ViewHolder
  public class NewsViewHolder extends BaseViewHolder<News> {  private TextView mTv_name;    private ImageView mImg_face;    private TextView mTv_sign;    public NewsViewHolder(ViewGroup parent) {        super(parent,R.layout.news_recycler_item);        mTv_name = $(R.id.person_name);        mTv_sign = $(R.id.person_sign);        mImg_face = $(R.id.person_face);    }    @Override    public void setData(final News data) {        mTv_name.setText(data.getTitle());        mTv_sign.setText(data.getCtime());        Glide.with(getContext())                .load(data.getPicUrl())                .placeholder(R.mipmap.ic_launcher)                .centerCrop()                .into(mImg_face);    }}

3.设置recycleview

recyclerView.setAdapter(adapter = new NewsAdapter(getActivity()));        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));        //添加边框        SpaceDecoration itemDecoration = new SpaceDecoration((int) PixUtil.convertDpToPixel(8, getContext()));        itemDecoration.setPaddingEdgeSide(true);        itemDecoration.setPaddingStart(true);        itemDecoration.setPaddingHeaderFooter(false);        recyclerView.addItemDecoration(itemDecoration);        //更多加载        adapter.setMore(R.layout.view_more, new RecyclerArrayAdapter.OnMoreListener() {            @Override            public void onMoreShow() {                getData();            }            @Override            public void onMoreClick() {            }        });        //写刷新事件        recyclerView.setRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {            @Override            public void onRefresh() {                recyclerView.postDelayed(new Runnable() {                    @Override                    public void run() {                        adapter.clear();                        page = 0;                        getData();                    }                }, 1000);            }        });        //点击事件        adapter.setOnItemClickListener(new RecyclerArrayAdapter.OnItemClickListener() {            @Override            public void onItemClick(int position) {                ArrayList<String> data = new ArrayList<String>();                data.add(adapter.getAllData().get(position).getPicUrl());                data.add(adapter.getAllData().get(position).getUrl());                Intent intent = new Intent(getActivity(), NewsDetailsActivity.class);                //用Bundle携带数据                Bundle bundle = new Bundle();                bundle.putStringArrayList("data", data);                intent.putExtras(bundle);                startActivity(intent);            }        });

Glide网络图片加载库

一个专注于平滑图片加载的库:

依赖:
compile 'com.github.bumptech.glide:glide:3.7.0'

基本使用:

Glide.with(mContext)                .load(path)                .asGif()                .override(300,300)                .diskCacheStrategy(DiskCacheStrategy.SOURCE)                .placeholder(R.drawable.progressbar)                .thumbnail(1f)                .error(R.drawable.error)                .transform(new MyBitmapTransformation(mContext,10f))                .into(iv);

新闻详情页

布局:使用CoordinatorLayout实现上拉toolbar压缩动画。

<?xml version="1.0" encoding="utf-8"?><android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    android:layout_width="match_parent"    android:layout_height="match_parent"    >    <android.support.design.widget.AppBarLayout        android:layout_width="match_parent"        android:layout_height="256dp"        android:fitsSystemWindows="true"        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">        <android.support.design.widget.CollapsingToolbarLayout            android:id="@+id/collapsing_toolbar"            android:layout_width="match_parent"            android:layout_height="match_parent"            android:fitsSystemWindows="true"            app:contentScrim="?attr/colorPrimary"            app:expandedTitleMarginEnd="64dp"            app:expandedTitleMarginStart="48dp"            app:layout_scrollFlags="scroll|exitUntilCollapsed">            <ImageView                android:src="@mipmap/ic_launcher"                android:id="@+id/ivImage"                android:layout_width="match_parent"                android:layout_height="match_parent"                android:fitsSystemWindows="true"                android:scaleType="centerCrop"                android:transitionName="新闻图片"                app:layout_collapseMode="parallax"                app:layout_collapseParallaxMultiplier="0.7" />            <android.support.v7.widget.Toolbar                android:id="@+id/toolbar"                android:layout_width="match_parent"                android:layout_height="?attr/actionBarSize"                app:layout_collapseMode="pin"                app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />        </android.support.design.widget.CollapsingToolbarLayout>    </android.support.design.widget.AppBarLayout>    <android.support.v4.widget.NestedScrollView        android:layout_width="match_parent"        android:layout_height="match_parent"        app:layout_behavior="@string/appbar_scrolling_view_behavior">        <WebView            android:id="@+id/web_text"            android:layout_width="match_parent"            android:layout_height="wrap_content"></WebView>    </android.support.v4.widget.NestedScrollView></android.support.design.widget.CoordinatorLayout>

CoordinatorLayout+AppBarLayout里面配合CollapsingToolbarLayout布局技能实现toolbar的动画:


my.gif

上面的Imgview加载图片,下面的webview加载文章内容

public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_news_detail);        toolbar.setTitle("新闻详情");        setSupportActionBar(toolbar);//        设置返回箭头        getSupportActionBar().setDisplayHomeAsUpEnabled(true);        toolbar.setNavigationOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                onBackPressed();            }        });        //新页面接收数据        Bundle bundle = this.getIntent().getExtras();        //接收name值        final ArrayList<String> data = bundle.getStringArrayList("data");        Log.d("url", data.get(0));        webText.setWebViewClient(new WebViewClient() {            @Override            public boolean shouldOverrideUrlLoading(WebView view, String url) {                // TODO Auto-generated method stub                view.loadUrl(url);                return true;            }        });        webText.loadUrl(data.get(1));        Glide.with(this)                .load(data.get(0)).error(R.mipmap.ic_launcher)                .fitCenter().into(ivImage);    }

到这里基本完成:最后动态添加fragment

//菜单事件添加if (id == R.id.nav_camera) {            // Handle the camera action            NewsFragment fragment=new NewsFragment();            FragmentManager fragmentManager=getSupportFragmentManager();            FragmentTransaction transaction=fragmentManager.beginTransaction();            transaction.replace(R.id.fragment_container,fragment);            transaction.commit();        }

效果测试:


my.gif

my.gif

总结:

只是勉强能用,还有很多细节没有优化。接下来好要继续学习。

补充:关于ButterKnife的使用

框架导入:
搜索依赖butterknife导入:

dependencies {    compile fileTree(include: ['*.jar'], dir: 'libs')    testCompile 'junit:junit:4.12'    compile 'com.android.support:appcompat-v7:24.2.0'    //依赖添加    compile 'com.jakewharton:butterknife:8.4.0'}

使用步骤:
注意我这里写的是8.40版本,和以前的有区别。
如果的ButterKnife是8.01或者以上的话
需要添加以下内容:
1.classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'

buildscript {    repositories {        jcenter()    }    dependencies {        classpath 'com.android.tools.build:gradle:2.1.2'        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'        // NOTE: Do not place your application dependencies here; they belong        // in the individual module build.gradle files    }}

2.apply plugin: 'com.neenbedankt.android-apt'

apply plugin: 'com.android.application'apply plugin: 'com.neenbedankt.android-apt'

3.apt 'com.jakewharton:butterknife-compiler:8.4.0'

dependencies {    compile fileTree(include: ['*.jar'], dir: 'libs')    testCompile 'junit:junit:4.12'    compile 'com.android.support:appcompat-v7:24.2.0'    //依赖添加    compile 'com.jakewharton:butterknife:8.4.0'    apt 'com.jakewharton:butterknife-compiler:8.4.0'}

Android Studio上方便使用butterknife注解框架的偷懒插件Android Butterknife Zelezny:


my.gif

技巧:鼠标要移动到布局文件名上。

文件已发至Github---https://github.com/HuRuWo/YiLan

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
2017 Android GitHub常用热门开源框架汇总
Android进阶——RecycleView的使用之自定义单选列表(二)
SmartRecom:一款干货满满,助你进阶的 App 项目
Android Studio上方便使用butterknife注解框架的偷懒插件Android Butterknife Zelezny
RecyclerView高级控件-附实例【android专题】
ButterKnife不同版本配置
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服