来源:自学PHP网 时间:2015-04-14 12:58 作者: 阅读:次
[导读] 跟着慕课网的教学视频学习了如何制作微信的主界面,因为还有一些地方并没有完全搞懂,所以这里主要是记录下整个制作的过程,方便以后的学习!效果图如图所示:实现了点击下面...
|
跟着慕课网的教学视频学习了如何制作微信的主界面,因为还有一些地方并没有完全搞懂,所以这里主要是记录下整个制作的过程,方便以后的学习! 效果图如图所示:
实现了点击下面tab切换fragment以及滑动切换tab的功能,同时滑动时,下面tab的icon会实现颜色渐变的效果。 首先是主界面的布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bunschen="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="@drawable/tab_bg"
android:orientation="horizontal">
<com.chen.weixin_6_0.ChangeIconColorWithText
android:id="@+id/tab_indicator_one"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
bunschen:Icon="@drawable/ic_menu_start_conversation"
bunschen:color="#FF008901"
bunschen:text="@string/app_name"
bunschen:text_size="12sp"/>
<com.chen.weixin_6_0.ChangeIconColorWithText
android:id="@+id/tab_indicator_two"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
bunschen:Icon="@drawable/ic_menu_friendslist"
bunschen:color="#FF008901"
bunschen:text="@string/tab_contact"
bunschen:text_size="12sp"/>
<com.chen.weixin_6_0.ChangeIconColorWithText
android:id="@+id/tab_indicator_three"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
bunschen:Icon="@drawable/ic_menu_emoticons"
bunschen:color="#FF008901"
bunschen:text="@string/tab_find"
bunschen:text_size="12sp"/>
<com.chen.weixin_6_0.ChangeIconColorWithText
android:id="@+id/tab_indicator_four"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
bunschen:Icon="@drawable/ic_menu_allfriends"
bunschen:color="#FF008901"
bunschen:text="@string/tab_me"
bunschen:text_size="12sp"/>
</LinearLayout>
</LinearLayout>
主界面采用线型布局,上面是自定义的ActionBar,中间内容区域是ViewPager+Fragment,下面的Tab区域是一个横向线型布局,其中每个View都是通过自定义布局实现。 1.自定义ActionBar:
//是更多菜单按钮显示出来
private void setOverflowShowingAlways() {
try {
ViewConfiguration config = ViewConfiguration.get(this);
Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
menuKeyField.setAccessible(true);
menuKeyField.setBoolean(config, false);
} catch (Exception e) {
e.printStackTrace();
}
}
该段是通过反射机制,将OverflowButton显示出来,因为在有菜单实体按键的手机中,屏幕中的菜单选项不会显示出来。
//是更多菜单按钮显示出来
private void setOverflowShowingAlways() {
try {
ViewConfiguration config = ViewConfiguration.get(this);
Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
menuKeyField.setAccessible(true);
menuKeyField.setBoolean(config, false);
} catch (Exception e) {
e.printStackTrace();
}
}
这段也是通过反射机制将Overflow菜单展开的菜单选项中将图标也显示出来,因为默认是将Overflow菜单展开的菜单选项的突变隐藏掉的。 菜单布局:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/action_settings"
android:actionViewClass="android.widget.SearchView"
android:icon="@drawable/actionbar_search_icon"
android:showAsAction="ifRoom|collapseActionView"
android:title="@string/action_search"
/>
<item
android:id="@+id/menu_contact"
android:icon="@drawable/menu_group_chat_icon"
android:title="@string/menu_contact"/>
<item
android:id="@+id/menu_add_friend"
android:icon="@drawable/menu_add_icon"
android:title="@string/menu_add_friend"/>
<item
android:id="@+id/menu_scan"
android:icon="@drawable/men_scan_icon"
android:title="@string/menu_contact"/>
<item
android:id="@+id/menu_feedback"
android:icon="@drawable/menu_feedback_icon"
android:title="@string/menu_feedback"/>
</menu>
接下来最主要的就是自定义View 首先是定义自定义的View需要的一些属性 values/attrs.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="Icon" format="reference"></attr>
<attr name="color" format="color"></attr>
<attr name="text" format="string"></attr>
<attr name="text_size" format="dimension"></attr>
<declare-styleable name="ChangeIconColorWithText">
<attr name="Icon"></attr>
<attr name="color"></attr>
<attr name="text"></attr>
<attr name="text_size"></attr>
</declare-styleable>
</resources>
然后是在布局文件中使用:
<com.chen.weixin_6_0.ChangeIconColorWithText
android:id="@+id/tab_indicator_one"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
bunschen:Icon="@drawable/ic_menu_start_conversation"
bunschen:color="#FF008901"
bunschen:text="@string/app_name"
bunschen:text_size="12sp"/>
注意这里的自定义的命名空间:
bunschen:Icon="@drawable/ic_menu_start_conversation"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bunschen="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
这里在开头自定义了命名空间,所以可以使用自定义的属性。 然后就是在构造函数中获取View:
public class ChangeIconColorWithText extends View {
private int mColor = 0xFF008901;
private Bitmap mIconBitmap;
private String mText = "微信";
private int mTextSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
12, getResources().getDisplayMetrics());
private Bitmap mBitmap;
private Canvas mCanvas;
private Paint mPaint;
private float alpha;
private Rect mTextBounds;
private Rect mBitmapBounds;
private Paint textPaint;
private final static String INSTANCE_STATUS = "instance_status";
private final static String ALPHA_STATUS = "alpha_status";
public ChangeIconColorWithText(Context context) {
this(context, null);
}
public ChangeIconColorWithText(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ChangeIconColorWithText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//获取到布局文件中定义的自定义控件的属性
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ChangeIconColorWithText);
int n = typedArray.getIndexCount();
//将这些属性赋值给该控件的成员变量
for (int i = 0; i < n; i++) {
int attr = typedArray.getIndex(i);
switch (attr) {
case R.styleable.ChangeIconColorWithText_color:
mColor = typedArray.getColor(attr, 0xFF0E4010);
break;
case R.styleable.ChangeIconColorWithText_Icon:
BitmapDrawable drawable = (BitmapDrawable) typedArray.getDrawable(attr);
mIconBitmap = drawable.getBitmap();
break;
case R.styleable.ChangeIconColorWithText_text:
mText = typedArray.getString(attr);
break;
case R.styleable.ChangeIconColorWithText_text_size:
mTextSize = (int) typedArray.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
12, getResources().getDisplayMetrics()));
break;
}
}
//回收掉使用的资源
typedArray.recycle();
mTextBounds = new Rect();
textPaint = new Paint();
textPaint.setTextSize(mTextSize);
textPaint.setColor(0xff555555);
textPaint.getTextBounds(mText, 0, mText.length(), mTextBounds);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//测量图标的宽度,长度与宽度一致
int iconWidth = Math.min(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
getMeasuredHeight() - getPaddingBottom() - getPaddingTop() - mTextBounds.height());
//测量图标绘制的位置的上下左右的值
int left = (getMeasuredWidth() - iconWidth)/2;
int top = (getMeasuredHeight() - mTextBounds.height() - iconWidth)/2;
//确定icon绘制的边界
mBitmapBounds = new Rect(left,top,left+iconWidth,top+iconWidth);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制出原无颜色的图标
canvas.drawBitmap(mIconBitmap,null,mBitmapBounds,null);
//ceil() 方法执行的是向上取整计算,它返回的是大于或等于函数参数,并且与之最接近的整数
int Alpha = (int) Math.ceil(255 * alpha);
// 内存去准备mBitmap , setAlpha , 纯色 ,xfermode , 图标
setupTargetBitmap(Alpha);
//1.绘制原文本。
setupSourceText(canvas,Alpha);
//2.绘制变色文本
setupTargetText(canvas,Alpha);
//将内存中绘制出的Bitmap对象绘制出来
canvas.drawBitmap(mBitmap,0,0,null);
}
//绘制带颜色的文本
private void setupTargetText(Canvas canvas, int alpha) {
textPaint.setColor(mColor);
textPaint.setAlpha(alpha);
//计算文本绘制的位置
float x = (getMeasuredWidth() - mTextBounds.width())/2;
float y = (mBitmapBounds.bottom + mTextBounds.height());
canvas.drawText(mText,x,y,textPaint);
}
//绘制原文本
private void setupSourceText(Canvas canvas, int alpha) {
textPaint.setAlpha(255 - alpha);
textPaint.setColor(0xff333333);
float x = (getMeasuredWidth() - mTextBounds.width())/2;
float y = (mBitmapBounds.bottom + mTextBounds.height());
canvas.drawText(mText,x,y,textPaint);
}
//在内存中绘制出icon
private void setupTargetBitmap(int alpha) {
mBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(),
Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
mPaint = new Paint();
mPaint.setColor(mColor);
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setAlpha(alpha);
mCanvas.drawRect(mBitmapBounds, mPaint);
//设置显示纯色区域与图标的交集区域,即显示的是图标以及颜色为纯色区域的颜色
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mPaint.setAlpha(255);
mCanvas.drawBitmap(mIconBitmap, null, mBitmapBounds, mPaint);
}
//设置alpha值
public void setAlphaView(float alpha){
this.alpha = alpha;
invalidateView();
}
//当alpha值变化时,重绘视 private void invalidateView() {
//判断是否是在UI线程
if(Looper.getMainLooper() == Looper.myLooper()){
invalidate();
}else{
postInvalidate();
}
}
//保存数据值及状态,防止Activity被系统销毁时在回到主界面时显示不正常的现象
@Override
protected Parcelable onSaveInstanceState() {
Bundle bundle = new Bundle();
bundle.putParcelable(INSTANCE_STATUS,super.onSaveInstanceState());
bundle.putFloat(ALPHA_STATUS,alpha);
return bundle;
}
//回复原先保存的数据值及状态
@Override
protected void onRestoreInstanceState(Parcelable state) {
if(state instanceof Bundle){
Bundle bundle = (Bundle) state;
alpha = bundle.getFloat(ALPHA_STATUS);
super.onRestoreInstanceState(bundle.getParcelable(INSTANCE_STATUS));
return;
}
super.onRestoreInstanceState(state);
}
}
然后是在MainActivity中实现滑动更新tab,以及点击tab更新fragment的逻辑:
public class MainActivity extends FragmentActivity implements View.OnClickListener, ViewPager.OnPageChangeListener {
private ViewPager viewPager;
//fragment中显示的文本内容
private String[] mTitles = new String[]{"first tab fragment", "second tab fragment",
"third tab fragment", "fourth tab fragment"};
private FragmentPagerAdapter mAdapter;
private List<Fragment> mData = new ArrayList<>();
//管理四个tab的List集合
private List<ChangeIconColorWithText> tabList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setOverflowShowingAlways();
getActionBar().setDisplayHomeAsUpEnabled(false);
initView();
initData();
viewPager.setAdapter(mAdapter);
viewPager.setOnPageChangeListener(this);
}
private void initData() {
for(String title : mTitles){
TabFragment tabFragment = new TabFragment();
Bundle bundle = new Bundle();
bundle.putString(TabFragment.TITLE,title);
tabFragment.setArguments(bundle);
mData.add(tabFragment);
}
mAdapter = new FragmentPagerAdapter(getSupportFragmentManager()) {
@Override
public Fragment getItem(int position) {
return mData.get(position);
}
@Override
public int getCount() {
return mData.size();
}
};
}
private void initView() {
viewPager = (ViewPager) findViewById(R.id.viewPager);
ChangeIconColorWithText one = (ChangeIconColorWithText) findViewById(R.id.tab_indicator_one);
tabList.add(one);
ChangeIconColorWithText two = (ChangeIconColorWithText) findViewById(R.id.tab_indicator_two);
tabList.add(two);
ChangeIconColorWithText three = (ChangeIconColorWithText) findViewById(R.id.tab_indicator_three);
tabList.add(three);
ChangeIconColorWithText four = (ChangeIconColorWithText) findViewById(R.id.tab_indicator_four);
tabList.add(four);
one.setOnClickListener(this);
two.setOnClickListener(this);
three.setOnClickListener(this);
four.setOnClickListener(this);
resetOtherTab();
one.setAlphaView(1);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
//是更多菜单按钮显示出来
private void setOverflowShowingAlways() {
try {
ViewConfiguration config = ViewConfiguration.get(this);
Field menuKeyField = ViewConfiguration.class
.getDeclaredField("sHasPermanentMenuKey");
menuKeyField.setAccessible(true);
menuKeyField.setBoolean(config, false);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public boolean onMenuOpened(int featureId, Menu menu) {
if (featureId == Window.FEATURE_ACTION_BAR && menu != null) {
if (menu.getClass().getSimpleName().equals("MenuBuilder")) {
try {
Method m = menu.getClass().getDeclaredMethod(
"setOptionalIconsVisible", Boolean.TYPE);
m.setAccessible(true);
m.invoke(menu, true);
} catch (Exception e) {
}
}
}
return super.onMenuOpened(featureId, menu);
}
@Override
public void onClick(View v) {
resetOtherTab();
switch(v.getId()){
case R.id.tab_indicator_one:
tabList.get(0).setAlphaView(1);
viewPager.setCurrentItem(0,false);
break;
case R.id.tab_indicator_two:
tabList.get(1).setAlphaView(1);
viewPager.setCurrentItem(1,false);
break;
case R.id.tab_indicator_three:
tabList.get(2).setAlphaView(1);
viewPager.setCurrentItem(2,false);
break;
case R.id.tab_indicator_four:
tabList.get(3).setAlphaView(1);
viewPager.setCurrentItem(3,false);
break;
}
}
private void resetOtherTab() { for(int i = 0; i < tabList.size(); i++){
tabList.get(i).setAlphaView(0);
}
}
//这里是在ViewPager滑动时,因为只有两个tab的颜色会发生变化,所以通过将他们的icon和文本颜色的alpha值进行改变,从而产生渐变的效果。
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if(positionOffset > 0){
ChangeIconColorWithText left = tabList.get(position);
ChangeIconColorWithText right = tabList.get(position + 1);
left.setAlphaView(1-positionOffset);
right.setAlphaView(positionOffset);
}
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
fragment:
public class TabFragment extends Fragment {
private static String mTitle = "default";
public static final String TITLE = "title";
@Override
public View onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState) {
TextView tv = new TextView(getActivity());
if(getArguments() != null) {
mTitle = getArguments().getString(TITLE);
}
tv.setText(mTitle);
tv.setTextSize(20);
tv.setTextColor(Color.BLACK);
tv.setGravity(Gravity.CENTER);
return tv;
}
}
基本内容就是这些,其中自定义View是难点,主要是自定义View中的绘制方法,XferMode的DST_IN方法。这里记录下来,以后慢慢学习。 |
自学PHP网专注网站建设学习,PHP程序学习,平面设计学习,以及操作系统学习
京ICP备14009008号-1@版权所有www.zixuephp.com
网站声明:本站所有视频,教程都由网友上传,站长收集和分享给大家学习使用,如由牵扯版权问题请联系站长邮箱904561283@qq.com