php专区

 首页 > php专区 > PHP应用 > 开放平台 > 仿微信主界面 - 微信公众平台开发:微信公众号

仿微信主界面 - 微信公众平台开发:微信公众号

分享到:
【字体:
导读:
          跟着慕课网的教学视频学习了如何制作微信的主界面,因为还有一些地方并没有完全搞懂,所以这里主要是记录下整个制作的过程,方便以后的学习!效果图如图所示:实现了点击下面...

跟着慕课网的教学视频学习了如何制作微信的主界面,因为还有一些地方并没有完全搞懂,所以这里主要是记录下整个制作的过程,方便以后的学习!

效果图如图所示:

实现了点击下面tab切换fragment以及滑动切换tab的功能,同时滑动时,下面tab的icon会实现颜色渐变的效果。

首先是主界面的布局:



    

    

        

        

        

        

    

activity_mian

主界面采用线型布局,上面是自定义的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菜单展开的菜单选项的突变隐藏掉的。

菜单布局:

  
      
  
     
 
     
 
     
 
     
 
 

接下来最主要的就是自定义View

首先是定义自定义的View需要的一些属性

values/attrs.xml:

  
  
 
      
      
      
      
      
      
         
         
         
         
     
 

然后是在布局文件中使用:

 

注意这里的自定义的命名空间:

bunschen:Icon="@drawable/ic_menu_start_conversation"

这里在开头自定义了命名空间,所以可以使用自定义的属性。

然后就是在构造函数中获取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 mData = new ArrayList<>();
      //管理四个tab的List集合
      private List 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批量生成带参数的二维...
带参数的二维码对于渠道营销推广来说是很有用的,可以获得多个带不同场景值的二维码,用户扫描后,公众号可以接收到事件推送,可喜的是微信开通了这个接口,那下面就来研究一下吧。 具体接口说明请参见,微信公众平台开发者文档 演示图: 由于带参数二维码生成是有限的,所有我是按编号生成的,下次生成的时候直接累加...
微信现金红包高级红包接口开发注意事项 ...
最近因为公司业务需求,接触了微信现金红包高级红包接口,开发时遇到了不少问题,网上搜索发现有很多人也遇到了各种问题,但是没有一个相对完整的解决方案。 在这里我把自己开发过程遇到的问题归纳一下,另外写了一个示例程序方便大家参考。 以下说明是基于Windows Microsoft .Net平台的。 官方文档:点击这里查看官方文...
  •         php迷,一个php技术的分享社区,专属您自己的技术摘抄本、收藏夹。
  • 在这里……