在模仿中循序渐进,以程序员角度去看待每一个APP是如何实现的,它有什么优缺点,并从中提升自己。
之前发现很多人在群里面、论坛上求网易新闻客户端的源码,之后我就去下了个网易新闻客户端和今日头条新闻客户端,发现他们的大体是一样的,于是在最近的空闲时间,便去琢磨如何去实现这样一个APP。
要知道它们是如何实现的,用到了什么第三方库文件,反编译便是很好的一个了解方法,如果你想要了解如何反编译可以点击这个链接:反编译就这么简单
只是一般的APK打包后都是被混淆过的,所以没那么好了解他的每个界面是如何实现的,没事,那就自己慢慢摸索或则从它的资源文件中提取布局了解下整体的大概情况。
我通过反编译 --今日头条:
知道了它用到的架包有,提取了有用的部分:
1.android-support-v4.jar (最常用的官方架包之一)
2.android-support-v7.jar (主要用于ActionBar的低版本兼容)
3.handmark.pulltorefresh.library (图片的下拉刷新包)
4.slidingmenu.lib (侧拉菜单包)
使用方法配置以及下载:点击这里
5.umeng(友盟的官方架包)
自己要在加用上的架包有:
1.Android-Universal-Image-Loader(图片的异步加载包)
使用方法配置以及下载:点击这里
注:发现架包中有aaa什么的命名,说明它被混淆过,所以要想进一步获取它的源码很困难,只能按照自己的思路去走。
好的,大体了解了它的整体结构,下面就开始它是如何开发的把:
注:本代码内用到的资源文件和属性配置部分从APK反编译的资源(SRC文件)中提取,为了达到更好的实现效果。
一.首先构建大体的框架,架包等用到的时候在导入
命名规范可以参考:android命名规范
二.进行配置
首先去掉应用的title栏目:
采取修改AndroidManifest.xml文件中application的android:theme="@style/AppTheme"属性:
<style name="AppTheme" parent="AppBaseTheme">
<item name="android:windowNoTitle">true</item>
</style>
三.开始开发
设置欢迎界面的调整动画,2秒
start_anima = new AlphaAnimation(0.3f, 1.0f);
start_anima.setDuration(2000);
view.startAnimation(start_anima);
start_anima.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animation animation) {
// TODO Auto-generated method stub
redirectTo();//跳转
}
});
之后便是主界面:
可以发现主界面上方的栏目栏是可以横向拖动的,并且选择。
下面就首先来实现上部栏目拖动这个效果:
大体思路结构图:
整体的布局文件是如下这样:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<include layout="@layout/main_head" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40.0dip"
android:background="#fff3f3f3"
android:orientation="horizontal" >
<RelativeLayout
android:id="@+id/rl_column"
android:layout_width="match_parent"
android:layout_height="40.0dip"
android:layout_weight="1.0" >
<com.topnews.view.ColumnHorizontalScrollView
android:id="@+id/mColumnHorizontalScrollView"
android:layout_width="match_parent"
android:layout_height="40.0dip"
android:scrollbars="none" >
<LinearLayout
android:id="@+id/mRadioGroup_content"
android:layout_width="fill_parent"
android:layout_height="40.0dip"
android:layout_centerVertical="true"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingLeft="10.0dip"
android:paddingRight="10.0dip" />
</com.topnews.view.ColumnHorizontalScrollView>
<ImageView
android:id="@+id/shade_left"
android:layout_width="10.0dip"
android:layout_height="40.0dip"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:background="@drawable/channel_leftblock"
android:visibility="gone" />
<ImageView
android:id="@+id/shade_right"
android:layout_width="10.0dip"
android:layout_height="40.0dip"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:background="@drawable/channel_rightblock"
android:visibility="visible" />
</RelativeLayout>
<LinearLayout
android:id="@+id/ll_more_columns"
android:layout_width="wrap_content"
android:layout_height="40.0dip" >
<ImageView
android:id="@+id/button_more_columns"
android:layout_width="40.0dip"
android:layout_height="40.0dip"
android:layout_gravity="center_vertical"
android:src="@drawable/channel_glide_day_bg" />
</LinearLayout>
</LinearLayout>
<View
android:id="@+id/category_line"
android:layout_width="fill_parent"
android:layout_height="0.5dip"
android:background="#ffdddddd" />
<android.support.v4.view.ViewPager
android:id="@+id/mViewPager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
由于发现HorizontalScrollView左右拖动的时候没有那种阴影效果,所以在这里,我们发现了头条的资源文件下有这么2个文件:
这个就是它在白天模式和黑夜模式下用的阴影图片。那我们可以采取重写HorizontalScrollView来判断滚动,如果滚动时候不是在最左边,显示左边阴影,不是在最右边,显示右边阴影。
public class ColumnHorizontalScrollView extends HorizontalScrollView {
/** 传入整体布局 */
private View ll_content;
/** 传入更多栏目选择布局 */
private View ll_more;
/** 传入拖动栏布局 */
private View rl_column;
/** 左阴影图片 */
private ImageView leftImage;
/** 右阴影图片 */
private ImageView rightImage;
/** 屏幕宽度 */
private int mScreenWitdh = 0;
/** 父类的活动activity */
private Activity activity;
public ColumnHorizontalScrollView(Context context) {
super(context);
}
public ColumnHorizontalScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ColumnHorizontalScrollView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
/**
* 在拖动的时候执行
* */
@Override
protected void onScrollChanged(int paramInt1, int paramInt2, int paramInt3, int paramInt4) {
// TODO Auto-generated method stub
super.onScrollChanged(paramInt1, paramInt2, paramInt3, paramInt4);
shade_ShowOrHide();
if(!activity.isFinishing() && ll_content !=null && leftImage!=null && rightImage!=null && ll_more!=null && rl_column !=null){
if(ll_content.getWidth() <= mScreenWitdh){
leftImage.setVisibility(View.GONE);
rightImage.setVisibility(View.GONE);
}
}else{
return;
}
if(paramInt1 ==0){
leftImage.setVisibility(View.GONE);
rightImage.setVisibility(View.VISIBLE);
return;
}
if(ll_content.getWidth() - paramInt1 + ll_more.getWidth() + rl_column.getLeft() == mScreenWitdh){
leftImage.setVisibility(View.VISIBLE);
rightImage.setVisibility(View.GONE);
return;
}
leftImage.setVisibility(View.VISIBLE);
rightImage.setVisibility(View.VISIBLE);
}
/**
* 传入父类布局中的资源文件
* */
public void setParam(Activity activity, int mScreenWitdh,View paramView1,ImageView paramView2, ImageView paramView3 ,View paramView4,View paramView5){
this.activity = activity;
this.mScreenWitdh = mScreenWitdh;
ll_content = paramView1;
leftImage = paramView2;
rightImage = paramView3;
ll_more = paramView4;
rl_column = paramView5;
}
/**
* 判断左右阴影的显示隐藏效果
* */
public void shade_ShowOrHide() {
if (!activity.isFinishing() && ll_content != null) {
measure(0, 0);
//如果整体宽度小于屏幕宽度的话,那左右阴影都隐藏
if (mScreenWitdh >= getMeasuredWidth()) {
leftImage.setVisibility(View.GONE);
rightImage.setVisibility(View.GONE);
}
} else {
return;
}
//如果滑动在最左边时候,左边阴影隐藏,右边显示
if (getLeft() == 0) {
leftImage.setVisibility(View.GONE);
rightImage.setVisibility(View.VISIBLE);
return;
}
//如果滑动在最右边时候,左边阴影显示,右边隐藏
if (getRight() == getMeasuredWidth() - mScreenWitdh) {
leftImage.setVisibility(View.VISIBLE);
rightImage.setVisibility(View.GONE);
return;
}
//否则,说明在中间位置,左、右阴影都显示
leftImage.setVisibility(View.VISIBLE);
rightImage.setVisibility(View.VISIBLE);
}
}
之后
private ArrayList<NewsClassify> newsClassify=new ArrayList<NewsClassify>();
根据newsClassify这个栏目分类列表里面的数量进行添加栏目。(这里首先采用了自己限定的ITEM,而没有进行数据库的操作,以后加上)
ViewPage的适配器NewsFragmentPagerAdapter,通过ViewPage切换对应栏目的的Fragment:
public class NewsFragmentPagerAdapter extends FragmentPagerAdapter {
private ArrayList<Fragment> fragments;
private FragmentManager fm;
public NewsFragmentPagerAdapter(FragmentManager fm) {
super(fm);
this.fm = fm;
}
public NewsFragmentPagerAdapter(FragmentManager fm,
ArrayList<Fragment> fragments) {
super(fm);
this.fm = fm;
this.fragments = fragments;
}
@Override
public int getCount() {
return fragments.size();
}
@Override
public Fragment getItem(int position) {
return fragments.get(position);
}
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
public void setFragments(ArrayList<Fragment> fragments) {
if (this.fragments != null) {
FragmentTransaction ft = fm.beginTransaction();
for (Fragment f : this.fragments) {
ft.remove(f);
}
ft.commit();
ft = null;
fm.executePendingTransactions();
}
this.fragments = fragments;
notifyDataSetChanged();
}
@Override
public Object instantiateItem(ViewGroup container, final int position) {
Object obj = super.instantiateItem(container, position);
return obj;
}
}
之后添加栏目ITEM:
int count = newsClassify.size();
for(int i = 0; i< count; i++){
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(mItemWidth , LayoutParams.WRAP_CONTENT);
params.leftMargin = 10;
params.rightMargin = 10;
TextView localTextView = new TextView(this);
localTextView.setTextAppearance(this, R.style.top_category_scroll_view_item_text);
localTextView.setBackgroundResource(R.drawable.radio_buttong_bg);
localTextView.setGravity(Gravity.CENTER);
localTextView.setPadding(5, 0, 5, 0);
localTextView.setId(i);
localTextView.setText(newsClassify.get(i).getTitle());
localTextView.setTextColor(getResources().getColorStateList(R.color.top_category_scroll_text_color_day));
if(columnSelectIndex == i){
localTextView.setSelected(true);
}
localTextView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
for(int i = 0;i < mRadioGroup_content.getChildCount();i++){
View localView = mRadioGroup_content.getChildAt(i);
if (localView != v)
localView.setSelected(false);
else{
localView.setSelected(true);
mViewPager.setCurrentItem(i);
}
}
Toast.makeText(getApplicationContext(), newsClassify.get(v.getId()).getTitle(), Toast.LENGTH_SHORT).show();
}
});
mRadioGroup_content.addView(localTextView, i ,params);
}
之后根据选择栏目的来调整ColumnHorizontalScrollView中的位置
/**
* 选择的Column里面的Tab
* */
private void selectTab(int tab_postion) {
columnSelectIndex = tab_postion;
for (int i = 0; i < mRadioGroup_content.getChildCount(); i++) {
View checkView = mRadioGroup_content.getChildAt(tab_postion);
int k = checkView.getMeasuredWidth();
int l = checkView.getLeft();
int i2 = l + k / 2 - mScreenWidth / 2;
// rg_nav_content.getParent()).smoothScrollTo(i2, 0);
mColumnHorizontalScrollView.smoothScrollTo(i2, 0);
// mColumnHorizontalScrollView.smoothScrollTo((position - 2) *
// mItemWidth , 0);
}
//判断是否选中
for (int j = 0; j < mRadioGroup_content.getChildCount(); j++) {
View checkView = mRadioGroup_content.getChildAt(j);
boolean ischeck;
if (j == tab_postion) {
ischeck = true;
} else {
ischeck = false;
}
checkView.setSelected(ischeck);
}
}
完成的效果如下:
更多注释和实现方法可以查看DEMO源码文件,源码下载地址 :
DEMO源码
第2篇已经优化完成点击以下链接:
(android高仿系列)今日头条
--新闻阅读器 (二)
分享到:
相关推荐
Android TopNews高仿... 高仿“今日头条”客户端,实现它大部分的功能,练习之作,目的了解怎么发开一个新闻类客户端,从涉及的相关知识点中提升自我水平。 [注意:本资源来自网络,如有侵权,请联系我删除,谢谢。]
这次实现的功能是很多新闻阅读器(网易,今日头条,360新闻等)以及腾讯视频等里面都会出现的频道管理功能。 对应博文地址:http://blog.csdn.net/vipzjyno1/article/details/25005851
Android 毕业设计高仿今日头条新闻客户端(内附源码) Android 毕业设计高仿今日头条新闻客户端(内附源码) Android 毕业设计高仿今日头条新闻客户端(内附源码) Android 毕业设计高仿今日头条新闻客户端(内附...
Android 高仿 频道管理----网易、今日头条(可以拖动的GridView)demo
(android高仿系列)今日头条 --新闻阅读器 (三) 完结 、总结 篇 实现了大体的全部功能。 对应的博文地址: http://blog.csdn.net/vipzjyno1/article/details/26514543 对应的GITHUB地址: ...
Android 高仿 频道管理----网易、今日头条(可以拖动的GridView)demo
(高仿)今日头条 源码 对应(android高仿系列)今日头条 --新闻阅读器 (一) 文章地址: http://blog.csdn.net/vipzjyno1/article/details/23591315 之后会一步一步实现这个客户端。
Android 源码 毕业设计高仿今日头条新闻客户端 App 现有功能: 1.获取各种频道的新闻列表,包括视频和非视频新闻; 2.查看新闻详情,包括视频和非视频新闻的详情; 3.查看新闻评论列表; 4.新闻数据本地存储,已经获取...
1.使用horizontalscollview实现头条新闻的效果,动态添加tab页面,2 本地缓存,记录条目数量
高仿今日头条网易新闻客户端Android应用源码
TopNews高仿“今日头条”客户端,1.slidingmenu 侧拉菜单 2.UniversalImageLoader ...高仿“今日头条”客户端,实现它大部分的功能,练习之作,目的了解怎么发开一个新闻类客户端,从涉及的相关知识点中提升自我水平。
Android 源码 毕业设计高仿今日头条新闻客户端 App 现有功能: 1.获取各种频道的新闻列表,包括视频和非视频新闻; 2.查看新闻详情,包括视频和非视频新闻的详情; 3.查看新闻评论列表; 4.新闻数据本地存储,已经获取...
高仿多看阅读器apk,支持PDF,EPUB,TXT解析.文档支持搜索,高亮文字,墨迹等功能
高仿今日头条新闻类资讯app,上下刷新,查看详情,以及视频优化!!!是一个值得推荐的新闻类app!!!
高仿今日头条android客户端源码,代码简便明了,逻辑性强.菜鸟小白一看就明白,值得收录.
高仿今日头条新闻资讯手机App网页版HTML5网页模板,下载下来可直接应用于H5版本网站开发,省去切图等前端工作。完整整套网站表态页面,可直接在浏览器中预览静态效果。
Android 源码 毕业设计高仿今日头条新闻客户端 App 文章地址:https://blog.csdn.net/JasonXu94/article/details/128821784 现有功能: 1.获取各种频道的新闻列表,包括视频和非视频新闻; 2.查看新闻详情,包括视频和...
高仿今日头条,网易新闻 有侧滑 选项卡 和增加新闻功能比较多,可以直接用
今日头条的指示器很炫酷,随着你的滑动字体颜色可以逐渐的变化,实现方法主要是使用自定义控件结合ViewPager。 CompleteTrackColorViewDemo实现高仿今日头条字体渐变指示器,滑动+点击切换,如丝顺滑