編輯:關於Android編程
這篇繼續解決上一篇遺留下來的問題:
點擊條目顯示具體的知乎日報信息怎麼實現?很簡單,讓ContentActivity的recylerView響應點擊事件便可。先來看看我的代碼結構吧,方便查看對應是哪個類。請看下圖:

ViewPager的點擊事件響應,本來一開始打算用setOnPageChangeListener來實現,但發現這個回調已經在實現輪詢播放的時候占用了並且每次滑動都會調用,所以不應該在這裡做處理。那麼只能在viewPager的adapter裡面加載頁面的時候做響應。RecylerClickListener是一個接口,用來響應條目的點擊事件,在ContentActivity實現這個接口。下面是HomeViewPagerAdapter:
package com.example.seaice.zhihuribao.adapter;
import android.support.v4.view.PagerAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.example.seaice.zhihuribao.R;
import com.example.seaice.zhihuribao.RecylerClickListener;
import com.example.seaice.zhihuribao.Utils.BaseApplication;
import com.example.seaice.zhihuribao.bean.HomeTopInfo;
import com.squareup.picasso.Picasso;
import java.util.List;
import butterknife.ButterKnife;
/**
* viewPager的adapter
* Created by seaice on 2016/8/18.
*/
public class HomeViewPagerAdapter extends PagerAdapter {
private List homeTopInfoList;
private RecylerClickListener mListener;
public HomeViewPagerAdapter(List imageViewList) {
this.homeTopInfoList = imageViewList;
}
//設置item listener
public void setOnItemClickListener(RecylerClickListener listener) {
this.mListener = listener;
}
@Override
public Object instantiateItem(ViewGroup viewGroup, final int position) {
LayoutInflater layoutInflater = LayoutInflater.from(BaseApplication.getApplication());
View RootView = layoutInflater.inflate(R.layout.top_view_pager, viewGroup, false);
//響應viewPager的點擊事件
RootView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mListener != null) {
mListener.onPagerClick(null, position);
}
}
});
ButterKnife.inject(RootView);
TextView topTitle = ButterKnife.findById(RootView, R.id.top_title);
ImageView topImage = ButterKnife.findById(RootView, R.id.top_image);
topTitle.setText(homeTopInfoList.get(position).getTitle());
Picasso.with(BaseApplication.getApplication()).load(homeTopInfoList.get(position).getImage()).fit().into(topImage);
viewGroup.addView(RootView);
return RootView;
}
@Override
public int getCount() {
return homeTopInfoList.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public void destroyItem(ViewGroup viewGroup, int position, Object object) {
viewGroup.removeView((View) object);
}
}
RecylerView對應條目的點擊事件,同樣也是調用RecylerClickListener這個接口來實現:
package com.example.seaice.zhihuribao;
import android.view.View;
public interface RecylerClickListener {
void onItemClck(View view, int position);//用於recyleview的普通item
void onPagerClick(View view, int position);//用於viewPager來實現
}
在HomeRecylerViewAdapter的MyViewHolder裡面實現點擊,調用這個接口。之前在MyViewHolder裡面的控件設置setOnClickListener都沒有效果,至今還沒弄清楚為啥?最後發現必須是設置Holder.itemView的click監聽才能實現點擊回調,這個需要注意一下,請看代碼:
//顯示日報條目的Holder
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public ImageView iv_title;
public TextView tv_title;
private RecylerClickListener listener;
public MyViewHolder(View view, RecylerClickListener listener) {
super(view);
iv_title = ButterKnife.findById(view, R.id.iv_title);
tv_title = ButterKnife.findById(view, R.id.tv_title);
this.listener = listener;
this.itemView.setOnClickListener(this);//必須是itemView才能設置
}
@Override
public void onClick(View v) {
LogUtils.e("myviewholder onclick");
if (listener != null) {
listener.onItemClck(v, getPosition() - 1);
}
}
}
ContentActivity實現RecylerClickListener接口,RecylerView的條目點擊後進入到日報的詳情頁面NewsInfoActivity:
//recyler條目點擊的回調
@Override
public void onItemClck(View view, int position) {
HomeStoriesInfo info = homeInfo.getHomeStoriesInfos().get(position);
Toast.makeText(this, info.getTitle(), Toast.LENGTH_SHORT).show();
String id = info.getId();
Intent intent = new Intent();
intent.putExtra("id", id);
intent.setClass(this, NewsInfoActivity.class);
startActivity(intent);
}
//viewpager點擊的回調
@Override
public void onPagerClick(View view, int position) {
HomeTopInfo info = homeInfo.getHomeTopInfoList().get(position);
String id = info.getId();
Intent intent = new Intent();
intent.putExtra("id", id);
intent.setClass(this, NewsInfoActivity.class);
startActivity(intent);
}
NewsInfoActivity就是顯示日報具體某條新聞的頁面,組成就是一條頂端的bar+webView。直接看布局文件:
NewsInfoActivity實際上不用做什麼操作,直接加載布局文件就搭建出頁面來了,當然部分功能未實現,先把大概寫出來吧。

package com.example.seaice.zhihuribao;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.example.seaice.zhihuribao.Utils.BaseApplication;
import com.example.seaice.zhihuribao.Utils.LogUtils;
import com.example.seaice.zhihuribao.Utils.ThreadMgr;
import com.example.seaice.zhihuribao.Utils.UiUtils;
import com.example.seaice.zhihuribao.bean.NewsBarInfo;
import com.example.seaice.zhihuribao.bean.NewsInfo;
import com.example.seaice.zhihuribao.protocol.NewsBarProtocol;
import com.example.seaice.zhihuribao.protocol.NewsItemProtocol;
import com.example.seaice.zhihuribao.view.NewsScrollView;
import com.squareup.picasso.Picasso;
import butterknife.ButterKnife;
import butterknife.InjectView;
public class NewsInfoActivity extends AppCompatActivity implements NewsScrollView.OnScrollListener {
@InjectView(R.id.webView)
WebView webView;
@InjectView(R.id.iv_news)
ImageView iv_news;
@InjectView(R.id.tv_title)
TextView tv_title;
@InjectView(R.id.tv_autor)
TextView tv_autor;
@InjectView(R.id.bar)
RelativeLayout rrBar;
@InjectView(R.id.newsScrollView)
NewsScrollView newsScrollView;
@InjectView(R.id.iv_back)
ImageView iv_back;
@InjectView(R.id.iv_share)
ImageView iv_share;
@InjectView(R.id.tv_collected)
ImageView tv_collected;
@InjectView(R.id.tv_comment)
TextView tv_comment;
@InjectView(R.id.tv_praise)
TextView tv_praise;
private NewsInfo newsInfo;
private NewsBarInfo barInfo;
private String id;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_news_info);
ButterKnife.inject(this);
initData();
initView();
}
private void initView() {
}
private void initData() {
Intent intent = getIntent();
id = intent.getStringExtra("id");
LogUtils.e(id);
Runnable runnable = new Runnable() {
@Override
public void run() {
NewsItemProtocol newsProtocol = new NewsItemProtocol(id);
newsInfo = newsProtocol.loadData();
NewsBarProtocol newsBarProtocol = new NewsBarProtocol(id);
barInfo = newsBarProtocol.loadData();
LogUtils.e(barInfo.toString());
UiUtils.runOnUiThread(new Runnable() {
@Override
public void run() {
setDisplayheader();
setWebViewDiplay();
setNewsBarDisplay();
}
});
}
};
ThreadMgr.getThreadPool().execute(runnable);
}
//設置頂部bar顯示
private void setNewsBarDisplay() {
tv_comment.setText(String.valueOf(barInfo.getComments()));
tv_praise.setText(String.valueOf(barInfo.getPopularity()));
}
//顯示文章的作者和題目
private void setDisplayheader() {
Picasso.with(BaseApplication.getApplication()).load(newsInfo.getImage()).into(iv_news);
tv_title.setText(newsInfo.getTitle());
tv_autor.setText(newsInfo.getImage_source());
}
//顯示webView
private void setWebViewDiplay() {
String css = "
"; String html = "" + css + "" + newsInfo.getBody() + ""; html = html.replace("
", ""); webView.getSettings().setJavaScriptEnabled(true); webView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS); webView.loadDataWithBaseURL(null, html, "text/html", "UTF-8", null); newsScrollView.setOnScrollListener(this); } //滑動頁面時,設置頂端bar的透明度 @Override public void onScroll(int scrollY) { float barAlpha = iv_news.getHeight() - scrollY; if (barAlpha <= 0) { barAlpha = 0; rrBar.setVisibility(View.GONE); rrBar.setAlpha(barAlpha); } else { barAlpha = barAlpha / iv_news.getHeight(); rrBar.setAlpha(barAlpha); rrBar.setVisibility(View.VISIBLE); } } public void pressBackBtn(View view) { finish(); } //分享 public void pressShareBtn(View view) { UiUtils.showToast("分享待實現"); } //收藏 public void pressCollectedBtn(View view) { UiUtils.showToast("收藏待實現"); } //評論 public void pressCommentBtn(View view) { Intent intent = new Intent(); Bundle bundle = new Bundle(); bundle.putString("id", id); bundle.putInt("comments", barInfo.getComments()); bundle.putInt("shortComment", barInfo.getShort_comments()); bundle.putInt("longComment", barInfo.getLong_comments()); intent.putExtras(bundle); intent.setClass(this, CommentActivity.class); startActivity(intent); } //點贊 public void pressPraiseBtn(View view) { UiUtils.showToast("點贊待實現"); } }
CommentActivity是顯示評論的界面,這裡順手也寫出來,同樣是頂端bar+RecylerView來實現。原版知乎日報的UI效果目前我還做不出來,只能先把大體顯示出來。布局文件activity_comment:

CommentActivity文件如下:
package com.example.seaice.zhihuribao;
import android.content.Context;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;
import android.widget.Button;
import android.widget.PopupWindow;
import android.widget.TextView;
import com.example.seaice.zhihuribao.Utils.BaseApplication;
import com.example.seaice.zhihuribao.Utils.LogUtils;
import com.example.seaice.zhihuribao.Utils.ThreadMgr;
import com.example.seaice.zhihuribao.Utils.UiUtils;
import com.example.seaice.zhihuribao.adapter.CommentRecylerViewAdapter;
import com.example.seaice.zhihuribao.bean.CommentsInfo;
import com.example.seaice.zhihuribao.protocol.CommentProtocol;
import butterknife.ButterKnife;
import butterknife.InjectView;
public class CommentActivity extends AppCompatActivity
implements CommentRecylerViewAdapter.CommentRecylerViewListemer, View.OnClickListener {
private String id;
private int commentsNum;
private CommentsInfo mLongCommentsInfo;
private CommentsInfo mShortCommentInfo;
private CommentRecylerViewAdapter adapter;
private PopupWindow popMenuWin;
@InjectView(R.id.tv_comments)
TextView tv_comments;
@InjectView(R.id.long_lv)
RecyclerView long_lv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_comment);
ButterKnife.inject(this);
initData();
initView();
}
private void initView() {
tv_comments.setText(String.valueOf(commentsNum + "個評論"));
}
private void initData() {
Bundle bundle = this.getIntent().getExtras();
id = bundle.getString("id");
commentsNum = bundle.getInt("comments");
Runnable runnable = new Runnable() {
@Override
public void run() {
CommentProtocol protocol = new CommentProtocol(id, true);
mLongCommentsInfo = protocol.loadData();
CommentProtocol shortProtocol = new CommentProtocol(id, false);
mShortCommentInfo = shortProtocol.loadData();
if (mLongCommentsInfo != null) {
UiUtils.runOnUiThread(new Runnable() {
@Override
public void run() {
LogUtils.e(mLongCommentsInfo.toString());
setLongLv();
}
});
}
}
};
ThreadMgr.getThreadPool().execute(runnable);
}
//設置recylerView
private void setLongLv() {
if (mLongCommentsInfo.getComments().size() > 0 || mShortCommentInfo.getComments().size() > 0) {
adapter = new CommentRecylerViewAdapter(mLongCommentsInfo, mShortCommentInfo);
adapter.setItemClickListener(this);
LinearLayoutManager layoutManager = new LinearLayoutManager(BaseApplication.getApplication());
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
long_lv.setLayoutManager(layoutManager);
long_lv.addItemDecoration(new SimpleDividerItemDecoration(BaseApplication.getApplication()));
long_lv.setAdapter(adapter);
}
}
//返回鍵
public void pressBackBtn(View view) {
finish();
}
//寫評論
public void writeCommentBtn(View view) {
Intent intent = new Intent();
intent.setClass(this, LogInActivity.class);
startActivity(intent);
}
//comment item click listener
@Override
public void onItemClickListener(View v, CommentsInfo.Comment comment) {
showPopupMenu(v);
}
//顯示彈出菜單
private void showPopupMenu(View v) {
dismissPopupMenu();
View contentView = View.inflate(BaseApplication.getApplication(), R.layout.popup_menu_win, null);
int screenWidth = getWindowManager().getDefaultDisplay().getWidth();
int screenHeight = getWindowManager().getDefaultDisplay().getHeight();
ScaleAnimation sa = new ScaleAnimation(0.5f, 1.0f, 0.5f, 1.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
sa.setDuration(300);
popMenuWin = new PopupWindow(contentView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
popMenuWin.setFocusable(true);
popMenuWin.setOutsideTouchable(true);
int[] location = new int[2];
v.getLocationInWindow(location);
popMenuWin.showAtLocation(v, Gravity.LEFT + Gravity.TOP, screenWidth/2, screenHeight / 2);
popMenuWin.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
setBackgroundAlpha(1.0f);
}
});
setBackgroundAlpha(0.5f);
contentView.startAnimation(sa);
Button btn_agree = ButterKnife.findById(contentView, R.id.pop_agree);
Button btn_jubao = ButterKnife.findById(contentView, R.id.pop_jubao);
Button btn_fuzhi = ButterKnife.findById(contentView, R.id.pop_fuzhi);
Button btn_reply = ButterKnife.findById(contentView, R.id.pop_reply);
btn_agree.setOnClickListener(this);
btn_jubao.setOnClickListener(this);
btn_fuzhi.setOnClickListener(this);
btn_reply.setOnClickListener(this);
}
//取消顯示框
private void dismissPopupMenu() {
if (popMenuWin != null && popMenuWin.isShowing()) {
popMenuWin.dismiss();
popMenuWin = null;
setBackgroundAlpha(1.0f);
}
}
//彈出框後背景變為半透明
private void setBackgroundAlpha(float bgAlpha) {
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.alpha = bgAlpha;
getWindow().setAttributes(lp);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.pop_agree:
UiUtils.showToast("待實現");
break;
case R.id.pop_jubao:
UiUtils.showToast("待實現");
break;
case R.id.pop_fuzhi:
UiUtils.showToast("待實現");
break;
case R.id.pop_reply:
UiUtils.showToast("待實現");
break;
default:break;
}
}
//添加recyclerview的divider
public class SimpleDividerItemDecoration extends RecyclerView.ItemDecoration {
private Drawable mDivider;
public SimpleDividerItemDecoration(Context context) {
mDivider = context.getResources().getDrawable(R.drawable.line_divider);
}
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
int left = parent.getPaddingLeft();
int right = parent.getWidth() - parent.getPaddingRight();
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int top = child.getBottom() + params.bottomMargin;
int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
}
@Override
protected void onDestroy() {
dismissPopupMenu();
super.onDestroy();
}
}
實際上來講,實現評論列表顯示的,還得靠RecylerView的Adapter,CommentRecylerViewAdapter:
package com.example.seaice.zhihuribao.adapter; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import com.example.seaice.zhihuribao.R; import com.example.seaice.zhihuribao.Utils.BaseApplication; import com.example.seaice.zhihuribao.bean.CommentsInfo; import com.squareup.picasso.Picasso; import java.util.List; import butterknife.ButterKnife; /** * Created by seaice on 2016/9/5. */ public class CommentRecylerViewAdapter extends RecyclerView.Adapter{ private static final int TYPE_LONG_HEADER = 0; private static final int TYPE_LONG_ITEM = 1; private static final int TYPE_SHORT_HEADER = 2; private static final int TYPE_SHORT_ITEM = 3; private CommentsInfo mLongCommentsInfo; private CommentsInfo mShortCommentInfo; private LayoutInflater mInflate; private CommentRecylerViewListemer mListener; public CommentRecylerViewAdapter(CommentsInfo mLongCommentsInfo, CommentsInfo mShortCommentInfo) { this.mLongCommentsInfo = mLongCommentsInfo; this.mShortCommentInfo = mShortCommentInfo; initData(); } private void initData() { mInflate = LayoutInflater.from(BaseApplication.getApplication()); } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == TYPE_LONG_HEADER) { View view = mInflate.inflate(R.layout.item_comment_header, parent, false); return new LongHeaderHolder(view); } else if (viewType == TYPE_SHORT_HEADER) { View view = mInflate.inflate(R.layout.item_comment_header, parent, false); return new ShortHeaderHolder(view); } else if (viewType == TYPE_LONG_ITEM) { View view = mInflate.inflate(R.layout.item_comment_view, parent, false); return new LongCommentsHolder(view); } else if (viewType == TYPE_SHORT_ITEM) { View view = mInflate.inflate(R.layout.item_comment_view, parent, false); return new ShortCommensHolder(view); } return null; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (holder instanceof LongHeaderHolder) { LongHeaderHolder lvh = (LongHeaderHolder) holder; lvh.longHeaderText.setText(mLongCommentsInfo.getComments().size() + "條長評論"); } else if (holder instanceof ShortHeaderHolder) { ShortHeaderHolder svh = (ShortHeaderHolder) holder; svh.shortHeaderText.setText(mShortCommentInfo.getComments().size() + "條短評論"); } else if (holder instanceof LongCommentsHolder) { CommentsInfo.Comment comment = mLongCommentsInfo.getComments().get(position - 1); LongCommentsHolder lvh = (LongCommentsHolder) holder; lvh.setComtentView(comment); } else if (holder instanceof ShortCommensHolder) { CommentsInfo.Comment comment = mShortCommentInfo.getComments().get(position - mLongCommentsInfo.getComments().size() - 2); ShortCommensHolder lvh = (ShortCommensHolder) holder; lvh.setComtentView(comment); } } @Override public int getItemCount() { return mLongCommentsInfo.getComments().size() + mShortCommentInfo.getComments().size() + 2; } @Override public int getItemViewType(int position) { if (isLongCommentHeader(position)) { return TYPE_LONG_HEADER; } else if (isShortCommentHeader(position)) { return TYPE_SHORT_HEADER; } else if (isLongCommentItem(position)) { return TYPE_LONG_ITEM; } else { return TYPE_SHORT_ITEM; } } //是否是短評論 private boolean isShortCommentItem(int position) { List comments = mShortCommentInfo.getComments(); if (position > mLongCommentsInfo.getComments().size() + 1 && comments.size() > 0) { return true; } return false; } //是否是長評論 private boolean isLongCommentItem(int position) { List comments = mLongCommentsInfo.getComments(); if (position > 0 && comments.size() > 0 && position <= comments.size()) { return true; } return false; } //是否是短評論的開頭 private boolean isShortCommentHeader(int position) { int count = mLongCommentsInfo.getComments().size() + 1; return position == count; } //是否是長評論的開頭 private boolean isLongCommentHeader(int position) { return position == 0; } //長評論 public class LongCommentsHolder extends BaseCommentsHolder { protected LongCommentsHolder(View view) { super(view); } } //短評論 public class ShortCommensHolder extends BaseCommentsHolder { protected ShortCommensHolder(View view) { super(view); } } //多少個長評論 public class LongHeaderHolder extends RecyclerView.ViewHolder { public TextView longHeaderText; public LongHeaderHolder(View view) { super(view); longHeaderText = ButterKnife.findById(view, R.id.tv_comment_header); } } //多少個短評論 public class ShortHeaderHolder extends RecyclerView.ViewHolder { public TextView shortHeaderText; public ShortHeaderHolder(View view) { super(view); shortHeaderText = ButterKnife.findById(view, R.id.tv_comment_header); } } public class BaseCommentsHolder extends RecyclerView.ViewHolder { public ImageView icon; public TextView author; public TextView likes; public TextView content; public TextView tvTime; public TextView tvExpand; protected BaseCommentsHolder(View view) { super(view); initView(view); } protected void initView(View view) { icon = ButterKnife.findById(view, R.id.iv_icon); author = ButterKnife.findById(view, R.id.tv_autor); likes = ButterKnife.findById(view, R.id.tv_likes); content = ButterKnife.findById(view, R.id.tv_content); tvTime = ButterKnife.findById(view, R.id.comment_time); tvExpand = ButterKnife.findById(view, R.id.tv_expand); } public void setComtentView(final CommentsInfo.Comment comment){ Picasso.with(BaseApplication.getApplication()).load(comment.getAvatar()).into(this.icon); this.author.setText(comment.getAuthor()); this.likes.setText(comment.getLikes()); this.content.setText(comment.getContent()); this.tvTime.setText(comment.getTime()); this.tvExpand.setText("zhangkai"); this.itemView.setBackgroundResource(R.drawable.ripple_bg); this.itemView.setClickable(true); this.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(mListener != null){ mListener.onItemClickListener(v, comment); } } }); } } public interface CommentRecylerViewListemer{ void onItemClickListener(View v, CommentsInfo.Comment comment); } public void setItemClickListener(CommentRecylerViewListemer listener){ this.mListener = listener; } }
好了,以上就基本的UI可以顯示出來了,盡管部分功能沒實現。現在就可以看到具體條目的新聞還有評論了。
下一篇,該實現什麼功能呢,我也不知道實現哪個功能,有點倦!
不過還是敬請期待吧!!
微信怎麼玩 微信好玩嗎
微信作為手機端通訊應用,很多人把它當做常用的通訊工具了,如果你還停留在QQ,還沒有開始使用微信的話,說明你就out了,微信功能強大,微信支付,微信叫滴滴,微
Android實現自定義的彈幕效果
一、效果圖先來看看效果圖吧~~二、實現原理方案1、自定義ViewGroup-XCDanmuView,繼承RelativeLayout來實現,當然也可以繼承其他三大布局類哈
Android官方底部Tab欄設計規范
上一篇《仿微信底部Tab欄》中粗略的講了下底部Tab欄的封裝,不少同學在實際運用中發現了一些問題,比如我demo中的title用了actionbar,所以如果新建的Act
calabash-android 命令行使用
本文介紹calabash-android的命令行的使用,通過例子,熟悉calabash-android所調用的ruby api和常用控制台命令, 如query, touc