如此抄袭Apps之OscHub(三)

有了第一篇博客上篇博客的介绍,结合大家的实践,相信对OscHub的基本框架有了清晰的认识。在这篇文章中,我们将完善应用的基本框架,让大家有一个对OscHub有个直观的认识。相信在学习了这篇文章后,朋友们对原代码(开源中国客户端)也会有更好进一步的了解。

这篇文章也将是“抄袭”开源中国客户端的一个终结,后续文章中,我将和大家一起研究该应用使用到的主要技术,包括View的自定义、表情符号的处理、网页内容的展示以及个别功能点的实现。在学习这些内容的同时,其实也是对OscHub的一个完善,最后呈现给大家的必将是一款高仿软件。

话不多说,开始今天内容的介绍。

上次我们已经在综合Tab中加入了两个子Tabs,包括资讯热点,接下来我们来添加剩下的两个子Tabs*博客推荐*。

其实,这两个子Tabs的实现,依旧遵照NewsFragment的实现思想,继承我们的BaseListFragment,根据传入的参数不同,来分别获取博客推荐的列表内容:

public class BlogFragment extends BaseListFragment<Blog> implements
        OnTabReselectListener {

    public static final String BUNDLE_BLOG_TYPE = "BUNDLE_BLOG_TYPE";

    protected static final String TAG = BlogFragment.class.getSimpleName();
    private static final String CACHE_KEY_PREFIX = "bloglist_";

    private String blogType;

    @Override
    protected BlogAdapter getListAdapter() {
        return new BlogAdapter();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Bundle args = getArguments();
        if (args != null) {
            blogType = args.getString(BUNDLE_BLOG_TYPE);
        }
    }

    @Override
    protected BlogList parseList(InputStream is) throws Exception {
        BlogList list = XmlUtils.toBean(BlogList.class, is);
        return list;
    }

    @Override
    protected BlogList readList(Serializable seri) {
        return ((BlogList) seri);
    }

    @Override
    protected void sendRequestData() {
        OSChinaApi.getBlogList(blogType, mCurrentPage, mHandler);
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position,
            long id) {

    }

    @Override
    public void onTabReselect() {
        onRefresh();
    }

}

同样地,我们需要一个对应的Adapter来适配我们的列表:

public class BlogAdapter extends ListBaseAdapter<Blog> {

    @Override
    protected View getRealView(int position, View convertView, ViewGroup parent) {
        ViewHolder vh = null;
        if (convertView == null || convertView.getTag() == null) {
            convertView = getLayoutInflater(parent.getContext()).inflate(
                    R.layout.list_cell_news, null);
            vh = new ViewHolder(convertView);
            convertView.setTag(vh);
        } else {
            vh = (ViewHolder) convertView.getTag();
        }

        Blog blog = mDatas.get(position);

        vh.tip.setVisibility(View.VISIBLE);
        if (blog.getDocumenttype() == Blog.DOC_TYPE_ORIGINAL) {
            vh.tip.setImageResource(R.drawable.widget_original_icon);
        } else {
            vh.tip.setImageResource(R.drawable.widget_repaste_icon);
        }

        vh.title.setText(blog.getTitle());

        vh.description.setVisibility(View.GONE);
        String description = blog.getBody();
        if (null != description && !StringUtils.isEmpty(description)) {
            vh.description.setVisibility(View.VISIBLE);
            vh.description.setText(description.trim());
        }

        vh.source.setText(blog.getAuthor());
        vh.time.setText(StringUtils.friendly_time(blog.getPubDate()));
        vh.comment_count.setText(blog.getCommentCount() + "");
        return convertView;
    }

    static class ViewHolder {

        @Bind(R.id.tv_title)
        TextView title;
        @Bind(R.id.tv_description)
        TextView description;
        @Bind(R.id.tv_source)
        TextView source;
        @Bind(R.id.tv_time)
        TextView time;
        @Bind(R.id.tv_comment_count)
        TextView comment_count;
        @Bind(R.id.iv_tip)
        ImageView tip;

        public ViewHolder(View view) {
            ButterKnife.bind(this, view);
        }
    }
}

有了这两个类,我们其实就已经完成了综合Tab的所有子Tabs的内容。不要忘记在NewsViewPagerFragment中加入我们新添加的两个Tabs哦:

 @Override
    protected void onSetupTabAdapter(ViewPageFragmentAdapter adapter) {
        String[] title = getResources().getStringArray(
                R.array.news_viewpage_arrays);
        adapter.addTab("news", title[0], NewsFragment.class,
                getBundle(NewsList.CATALOG_ALL));
        adapter.addTab("news_week", title[1], NewsFragment.class,
                getBundle(NewsList.CATALOG_WEEK));
        adapter.addTab("latest_blog", title[2], BlogFragment.class,
                getBundle(BlogList.CATALOG_LATEST));
        adapter.addTab("recommend_blog", title[3], BlogFragment.class,
                getBundle(BlogList.CATALOG_RECOMMEND));
    }

好了,介绍完了综合Tab的内容,下面我们继续介绍与其实现极其类似的另一个Tab——动弹

动弹Tab同样需要一个ViewPagerFragment类和其子Tabs用到的Fragment类。在原代码中,它们分别是TweetsViewPagerFragment类和TweetsFragment类。与综合Tab不同的是,动弹Tab虽然包括了3个子Tabs,但是它们使用了同一个Fragment类,即TweetsFragment

TweetsViewPagerFragment类的实现与NewsViewPagerFragment类的实现如出一辙,实现上并没有什么特殊的变化:

public class TweetsViewPagerFragment extends BaseViewPagerFragment implements OnTabReselectListener {

    @Override
    protected void onSetupTabAdapter(ViewPageFragmentAdapter adapter) {

        String[] title = getResources().getStringArray(
                R.array.tweets_viewpage_arrays);
        adapter.addTab("new_tweets", title[0], TweetsFragment.class,
                getBundle(TweetsList.CATALOG_LATEST));
        adapter.addTab("hot_tweets", title[1], TweetsFragment.class,
                getBundle(TweetsList.CATALOG_HOT));
        adapter.addTab("my_tweets", title[2], TweetsFragment.class,
                getBundle(TweetsList.CATALOG_ME));
    }

    private Bundle getBundle(int catalog) {
        Bundle bundle = new Bundle();
        bundle.putInt(BaseListFragment.BUNDLE_KEY_CATALOG, catalog);
        return bundle;
    }

    @Override
    public void initData() {
    }

    @Override
    public void onTabReselect() {
        try {
            int currentIndex = mViewPager.getCurrentItem();
            Fragment currentFragment = getChildFragmentManager().getFragments()
                    .get(currentIndex);
            if (currentFragment != null
                    && currentFragment instanceof OnTabReselectListener) {
                OnTabReselectListener listener = (OnTabReselectListener) currentFragment;
                listener.onTabReselect();
            }
        } catch (NullPointerException e) {
        }
    }
}

TweetsFragment类的实现上,也完全遵照NewsFragment的实现思路:

public class TweetsFragment extends BaseListFragment<Tweet> implements
        OnItemLongClickListener, OnTabReselectListener {

    protected static final String TAG = TweetsFragment.class.getSimpleName();
    private static final String CACHE_KEY_PREFIX = "tweetslist_";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    protected TweetAdapter getListAdapter() {
        return new TweetAdapter();
    }

    public String getTopic() {
        Bundle bundle = getArguments();
        if (bundle != null) {
            String str = bundle.getString("topic");
            if (str != null) {
                return str;
            }
        }
        return "";
    }

    @Override
    protected TweetsList parseList(InputStream is) throws Exception {
        TweetsList list = XmlUtils.toBean(TweetsList.class, is);
        return list;
    }

    @Override
    protected TweetsList readList(Serializable seri) {
        return ((TweetsList) seri);
    }

    @Override
    protected void sendRequestData() {
        Bundle bundle = getArguments();
        if (bundle != null) {
            String str = bundle.getString("topic");
            if (str != null) {
                OSChinaApi.getTweetTopicList(mCurrentPage, str, mHandler);
                return;
            }
        }
        OSChinaApi.getTweetList(mCatalog, mCurrentPage, mHandler);
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position,
            long id) {

    }

    protected void requestData(boolean refresh) {
        if (mCatalog > 0) {

            mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR);
            mErrorLayout.setErrorMessage(getString(R.string.unlogin_tip));
        } else {
            super.requestData();
        }
    }

    @Override
    public void initView(View view) {
        super.initView(view);
        mListView.setOnItemLongClickListener(this);
        mErrorLayout.setOnLayoutClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                if (mCatalog > 0) {

                } else {
                    mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING);
                    requestData(true);
                }
            }
        });
    }

    @Override
    public boolean onItemLongClick(AdapterView<?> parent, View view,
            int position, long id) {
        return false;
    }

    @Override
    public void onTabReselect() {
        onRefresh();
    }

}

唯一不同的是,其在展示内容的适配器上。在展示用户的动弹时,不仅仅要展示发布动弹的用户头像,还要展示其多样的动弹内容。现在的问题时,我们不能预知用户会发送什么类型的动弹,所以在原代码中引入了LinkMovementMethod类和URLSpan类,也提供了一些处理内容的工具类,比如InputHelperTypefaceUtils等工具类。这些类或者方法主要用于处理用户发送内容中的链接表情符号等。由于这些类与具体的业务关系不大,我这里暂不铺开陈述,有兴趣的朋友可以参考源码来学习。在后续的博客中,我也将会把一些个人觉得比较关键和重要的类和方法介绍给大家,并结合原代码讲解其使用的场景。

 @Override
    protected View getRealView(final int position, View convertView,
            final ViewGroup parent) {
        context = parent.getContext();
        final ViewHolder vh;
        if (convertView == null || convertView.getTag() == null) {
            convertView = getLayoutInflater(parent.getContext()).inflate(
                    R.layout.list_cell_tweet, null);
            vh = new ViewHolder(convertView);
            convertView.setTag(vh);
        } else {
            vh = (ViewHolder) convertView.getTag();
        }
        final Tweet tweet = mDatas.get(position);

        vh.del.setVisibility(View.GONE);
        vh.author.setText(tweet.getAuthor());
        vh.time.setText(StringUtils.friendly_time(tweet.getPubDate()));
        vh.content.setMovementMethod(MyLinkMovementMethod.a());
        vh.content.setFocusable(false);
        vh.content.setDispatchToParent(true);
        vh.content.setLongClickable(false);

        Spanned span = Html.fromHtml(tweet.getBody().trim());

        if (!StringUtils.isEmpty(tweet.getAttach())) {

            SpannableString str = new SpannableString("c");
            vh.content.setText(str);
            span = InputHelper.displayEmoji(context.getResources(), span);
            vh.content.append(span);
        } else {
            span = InputHelper.displayEmoji(context.getResources(), span);
            vh.content.setText(span);
        }
        MyURLSpan.parseLinkText(vh.content, span);

        vh.commentcount.setText(tweet.getCommentCount() + "");
        tweet.setLikeUsers(context, vh.likeUsers, true);
        final ViewHolder vh1 = vh;
        if (tweet.getLikeUser() == null) {
            vh.tvLikeState.setVisibility(View.GONE);
        }
        TypefaceUtils.setTypeface(vh.tvLikeState);
        if (tweet.getIsLike() == 1) {
            vh.tvLikeState.setTextColor(AppContext.getInstance().getResources().getColor(R.color.day_colorPrimary));
        } else {
            vh.tvLikeState.setTextColor(AppContext.getInstance().getResources().getColor(R.color.gray));
        }
        PlatfromUtil.setPlatFromString(vh.platform, tweet.getAppclient());

        return convertView;
    }

有了上面的两个类,我们的应用框架基本上就已经完整了,其它列表的实现不过这两类列表的变种(除了开源软件->分类列表,这个在后面我会重点介绍,这里暂且不表)。

另外两个主Tabs——发现Tab我Tab主要是几个功能的入口,每一个功能的实现有其自己的特点。我个人觉得没必要针对它们的实现来一一给大家介绍,所以后面我会挑选个人觉得比较好的功能来跟大家一起学习。

好了,我们的“抄袭”开源中国客户端之路就告一段落了,后面我会根据不同的功能还和大家一起学习研究,同时也会将之前遗留的个人觉得比较重要的知识点来与大家一起分享,比如列表的下拉刷新,圆形头像的处理等等。敬请期待。

最后,附上本期的运行效果图和源码下载地址:

运行效果图

源码下载,请出门左转

Commit版本:60f828

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值