首页 > 系统 > Android > 正文

Android仿微信公众号界面

2019-10-22 18:09:52
字体:
来源:转载
供稿:网友

最近在做一个关于微信公众平台服务号的小项目,主要用来实现排队叫号功能。一直都对微信公众号开发比较好奇,于是趁这次机会仔细研究了一下公众号的开发流程和逻辑架构。

微信公众平台现在分为3类:订阅号,服务号和企业号。其中,服务号和企业号的开放权限比较高,可以实现自定义菜单功能,调用摄像头以及LBS等API。

基本通信架构如图:

Android,微信公众号

在项目的功能设计阶段本想搭建一个服务号Demo用来展示,但微信服务号的认证手续太麻烦,而且我也没有那个资质去开通服务号。于是打算自己做一个仿微信公众号的基本界面,先实现菜单功能,避免开发初期的公众号注册,同时也方便展示。

先上效果图:

Android,微信公众号 Android,微信公众号 Android,微信公众号

1. 界面布局

主界面布局四部分,由上到下依次是:标题栏,消息列表,底部菜弹出的子菜单,底部菜单或输入栏。

主界面基本框架main.xml代码如下:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"   xmlns:tools="http://schemas.android.com/tools"   android:id="@+id/main"   android:layout_width="match_parent"   android:layout_height="match_parent"   android:background="#E4E4E4" >    <!-- 消息列表 -->    <ListView     android:id="@+id/lv"     android:layout_width="fill_parent"     android:layout_height="fill_parent"     android:layout_marginBottom="50dp"     android:layout_marginTop="10dp"     android:cacheColorHint="#00000000"     android:divider="#00000000"     android:dividerHeight="20dp"     android:scrollbars="none" >   </ListView>    <!-- 点击底部菜单后弹出的子菜单 -->    <LinearLayout     android:layout_width="fill_parent"     android:layout_height="wrap_content"     android:layout_gravity="bottom"     android:layout_marginBottom="50dp"     android:orientation="horizontal" >      <View       android:layout_width="0dp"       android:layout_height="wrap_content"       android:layout_weight="0.5" />      <LinearLayout       android:id="@+id/pop_layout1"       android:layout_width="0dp"       android:layout_height="wrap_content"       android:layout_gravity="bottom"       android:layout_weight="1"       android:orientation="vertical" >     </LinearLayout>      <LinearLayout       android:id="@+id/pop_layout2"       android:layout_width="0dp"       android:layout_height="wrap_content"       android:layout_gravity="bottom"       android:layout_weight="1"       android:orientation="vertical" >     </LinearLayout>      <LinearLayout       android:id="@+id/pop_layout3"       android:layout_width="0dp"       android:layout_height="wrap_content"       android:layout_gravity="bottom"       android:layout_weight="1"       android:orientation="vertical" >     </LinearLayout>   </LinearLayout>      <!-- 底部菜单 -->    <LinearLayout     android:id="@+id/bottom_layout"     android:layout_width="fill_parent"     android:layout_height="50dp"     android:layout_gravity="bottom"     android:background="#00ffffff"     android:orientation="vertical" >      <LinearLayout       android:id="@+id/bottom_menu_layout1"       android:layout_width="fill_parent"       android:layout_height="fill_parent"       android:background="#ffffff"       android:orientation="vertical" >        <View         android:layout_width="fill_parent"         android:layout_height="1px"         android:background="#A6A6A6" />        <LinearLayout         android:id="@+id/menu_layout"         android:layout_width="fill_parent"         android:layout_height="fill_parent"         android:gravity="center"         android:orientation="horizontal" >          <ImageView           android:id="@+id/keyboard"           android:layout_width="0dp"           android:layout_height="wrap_content"           android:layout_marginBottom="5dp"           android:layout_marginLeft="3dp"           android:layout_marginRight="3dp"           android:layout_marginTop="5dp"           android:layout_weight="0.5"           android:background="@drawable/keyboard" />          <View           android:layout_width="1px"           android:layout_height="fill_parent"           android:background="#A6A6A6" />          <RelativeLayout           android:id="@+id/btn1"           android:layout_width="0dp"           android:layout_height="fill_parent"           android:layout_weight="1"           android:background="@drawable/btn_selector" >            <RelativeLayout             android:layout_width="fill_parent"             android:layout_height="fill_parent"             android:layout_margin="5dp" >              <TextView               android:id="@+id/text1"               android:layout_width="fill_parent"               android:layout_height="fill_parent"               android:layout_centerInParent="true"               android:gravity="center"               android:text="用户绑定"               android:textColor="#000000"               android:textSize="16sp" />              <ImageView               android:layout_width="10dp"               android:layout_height="10dp"               android:layout_alignParentBottom="true"               android:layout_alignParentRight="true"               android:src="@drawable/more_icon"               android:visibility="invisible" />           </RelativeLayout>         </RelativeLayout>          <View           android:layout_width="1px"           android:layout_height="fill_parent"           android:background="#A6A6A6" />          <RelativeLayout           android:id="@+id/btn2"           android:layout_width="0dp"           android:layout_height="fill_parent"           android:layout_weight="1"           android:background="@drawable/btn_selector" >            <RelativeLayout             android:layout_width="fill_parent"             android:layout_height="fill_parent"             android:layout_margin="5dp" >              <TextView               android:id="@+id/text2"               android:layout_width="fill_parent"               android:layout_height="fill_parent"               android:layout_centerInParent="true"               android:gravity="center"               android:text="扫描签到"               android:textColor="#000000"               android:textSize="16sp" />              <ImageView               android:layout_width="10dp"               android:layout_height="10dp"               android:layout_alignParentBottom="true"               android:layout_alignParentRight="true"               android:src="@drawable/more_icon"               android:visibility="invisible" />           </RelativeLayout>         </RelativeLayout>          <View           android:layout_width="1px"           android:layout_height="fill_parent"           android:background="#A6A6A6" />          <RelativeLayout           android:id="@+id/btn3"           android:layout_width="0dp"           android:layout_height="fill_parent"           android:layout_weight="1"           android:background="@drawable/btn_selector" >            <RelativeLayout             android:layout_width="fill_parent"             android:layout_height="fill_parent"             android:layout_margin="5dp" >              <TextView               android:id="@+id/text3"               android:layout_width="fill_parent"               android:layout_height="fill_parent"               android:layout_centerInParent="true"               android:gravity="center"               android:text="更多"               android:textColor="#000000"               android:textSize="16sp" />              <ImageView               android:layout_width="10dp"               android:layout_height="10dp"               android:layout_alignParentBottom="true"               android:layout_alignParentRight="true"               android:src="@drawable/more_icon"               android:visibility="visible" />           </RelativeLayout>         </RelativeLayout>       </LinearLayout>     </LinearLayout>   </LinearLayout>  </FrameLayout> 

标题栏title_bar.xml布局如下:

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"   android:layout_width="fill_parent"   android:layout_height="fill_parent"   android:orientation="horizontal" >    <!-- 返回 -->    <ImageView     android:id="@+id/title_bar_back_btn"     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:layout_alignParentLeft="true"     android:layout_centerVertical="true"     android:layout_marginLeft="10dip"     android:src="@drawable/back" />      <!-- 服务号名称 -->    <TextView     android:id="@+id/my_setting_title_tv"     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:layout_centerInParent="true"     android:text="腾讯招聘面试服务"     android:textColor="#ffffff"     android:textSize="20sp" />      <!-- 服务号 -->    <ImageView     android:id="@+id/title_bar_my"     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:layout_alignParentRight="true"     android:layout_centerVertical="true"     android:layout_marginRight="10dip"     android:src="@drawable/my" />  </RelativeLayout> 

完成title_bar布局后,再在values/styles.xml添加自定义标题栏主题

<!-- 自定义标题栏背景颜色 -->   <style name="CustomWindowTitleBackground">     <item name="android:background">#32394A</item>   </style>    <!-- 自定义标题栏主题 -->   <style name="myTheme" parent="android:Theme">     <item name="android:windowTitleSize">45dp</item>     <item name="android:windowTitleBackgroundStyle">@style/CustomWindowTitleBackground</item> </style> 

消息列表的服务端消息item布局item_left.xml

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"   android:layout_width="match_parent"   android:layout_height="match_parent"   android:orientation="horizontal" >    <RelativeLayout     android:layout_width="0dp"     android:layout_height="fill_parent"     android:layout_weight="4" >     <ImageView       android:id="@+id/server_image"        android:layout_width="40dp"       android:layout_height="40dp"       android:layout_marginLeft="2dp"       android:background="@drawable/qq"/>     <TextView        android:id="@+id/server_text"       android:layout_width="wrap_content"       android:layout_height="wrap_content"       android:layout_marginLeft="2dp"       android:layout_toRightOf="@id/server_image"       android:background="@drawable/text_bg_left1"       android:gravity="center_vertical|left"       android:textSize="16sp"       android:textColor="#000000"/>   </RelativeLayout>    <View     android:layout_width="0dp"     android:layout_height="fill_parent"     android:layout_weight="1" />  </LinearLayout> 

消息列表的用户消息item布局item_right.xml

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"   android:layout_width="match_parent"   android:layout_height="match_parent"   android:orientation="horizontal" >    <View     android:layout_width="0dp"     android:layout_height="fill_parent"     android:layout_weight="1" />    <RelativeLayout     android:layout_width="0dp"     android:layout_height="fill_parent"     android:layout_weight="4" >      <ImageView       android:id="@+id/user_image"       android:layout_width="40dp"       android:layout_height="40dp"       android:layout_alignParentRight="true"       android:layout_marginRight="2dp"       android:background="@drawable/qq" />      <TextView       android:id="@+id/user_text"       android:layout_width="wrap_content"       android:layout_height="wrap_content"       android:layout_marginRight="1dp"       android:layout_toLeftOf="@id/user_image"       android:background="@drawable/text_bg_right1"       android:gravity="center_vertical|right"       android:textColor="#000000"       android:textSize="16sp" />   </RelativeLayout>  </LinearLayout> 

弹出的子菜单布局child_menu.xml如下:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"   android:id="@+id/child_layout"   android:layout_width="wrap_content"   android:layout_height="wrap_content"   android:background="#FFFFFF"   android:gravity="bottom"   android:orientation="vertical" >    <RelativeLayout     android:layout_width="wrap_content"     android:layout_height="wrap_content" >      <Button       android:id="@+id/test1"       android:layout_width="wrap_content"       android:layout_height="45dp"       android:background="@drawable/btn_selector"       android:paddingLeft="10dp"       android:paddingRight="10dp"       android:text="进度查询"       android:textColor="#000000"       android:textSize="16sp" />      <View       android:layout_width="wrap_content"       android:layout_height="1px"       android:layout_alignLeft="@id/test1"       android:layout_alignRight="@id/test1"       android:layout_below="@id/test1"       android:background="#E4E4E4" />   </RelativeLayout>    <RelativeLayout     android:layout_width="wrap_content"     android:layout_height="wrap_content" >      <Button       android:id="@+id/test1"       android:layout_width="wrap_content"       android:layout_height="45dp"       android:background="@drawable/btn_selector"       android:paddingLeft="10dp"       android:paddingRight="10dp"       android:text="使用帮助"       android:textColor="#000000"       android:textSize="16sp" />      <View       android:layout_width="wrap_content"       android:layout_height="1px"       android:layout_alignLeft="@id/test1"       android:layout_alignRight="@id/test1"       android:layout_below="@id/test1"       android:background="#E4E4E4" />   </RelativeLayout>    <RelativeLayout     android:layout_width="wrap_content"     android:layout_height="wrap_content" >      <Button       android:id="@+id/test1"       android:layout_width="wrap_content"       android:layout_height="45dp"       android:background="@drawable/btn_selector"       android:paddingLeft="10dp"       android:paddingRight="10dp"       android:text="联系我们"       android:textColor="#000000"       android:textSize="16sp" />      <View       android:layout_width="wrap_content"       android:layout_height="1px"       android:layout_alignLeft="@id/test1"       android:layout_alignRight="@id/test1"       android:layout_below="@id/test1"       android:background="#E4E4E4" />   </RelativeLayout>  </LinearLayout> 

由底部菜单切换到输入框,输入框bottom_menu_layout2.xml布局如下:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"   android:layout_width="match_parent"   android:layout_height="match_parent"   android:orientation="vertical" >    <LinearLayout     android:id="@+id/bottom_menu_layout2"     android:layout_width="fill_parent"     android:layout_height="fill_parent"     android:background="#ffffff"     android:orientation="vertical" >      <View       android:layout_width="fill_parent"       android:layout_height="1px"       android:background="#A6A6A6" />      <LinearLayout       android:id="@+id/menu_layout"       android:layout_width="fill_parent"       android:layout_height="fill_parent"       android:gravity="center"       android:orientation="horizontal" >        <!-- 左侧切换菜单按钮 -->        <ImageView         android:id="@+id/menu"         android:layout_width="0dp"         android:layout_height="wrap_content"         android:layout_marginBottom="5dp"         android:layout_marginLeft="3dp"         android:layout_marginRight="3dp"         android:layout_marginTop="5dp"         android:layout_weight="0.5"         android:background="@drawable/menu" />        <View         android:layout_width="1px"         android:layout_height="fill_parent"         android:background="#A6A6A6" />        <RelativeLayout         android:id="@+id/btn1"         android:layout_width="0dp"         android:layout_height="fill_parent"         android:layout_margin="5dp"         android:layout_weight="3"         android:background="#ffffff" >          <ImageView           android:id="@+id/voice"           android:layout_width="wrap_content"           android:layout_height="wrap_content"           android:layout_alignParentLeft="true"           android:layout_centerInParent="true"           android:layout_marginLeft="5dp"           android:src="@drawable/voice" />           <!-- 右侧“+”按钮或发送按钮 -->          <Button           android:id="@+id/add"           android:layout_width="wrap_content"           android:layout_height="wrap_content"           android:layout_alignParentRight="true"           android:layout_centerInParent="true"           android:layout_marginRight="1dp"           android:background="@drawable/add"           android:paddingBottom="5dp"           android:paddingLeft="8dp"           android:paddingRight="8dp"           android:paddingTop="5dp"           android:text=""           android:textColor="#ffffff"           android:textSize="14sp" />          <!-- 输入 -->          <RelativeLayout           android:layout_width="fill_parent"           android:layout_height="wrap_content"           android:layout_centerInParent="true"           android:layout_marginLeft="5dp"           android:layout_marginRight="5dp"           android:layout_toLeftOf="@id/add"           android:layout_toRightOf="@id/voice" >            <EditText             android:id="@+id/input_text"             android:layout_width="fill_parent"             android:layout_height="wrap_content"             android:layout_centerVertical="true"             android:background="#00000000"             android:gravity="bottom"             android:paddingLeft="2dp"             android:paddingRight="2dp"             android:text=""             android:textColor="#000000"             android:textSize="16sp" />            <View             android:layout_width="fill_parent"             android:layout_height="1px"             android:layout_below="@id/input_text"             android:layout_marginTop="10dp"             android:background="#A6A6A6" />         </RelativeLayout>       </RelativeLayout>     </LinearLayout>   </LinearLayout>  </LinearLayout> 

2. 代码实现

MainActivity.java

 

package com.example.wxdemo;  import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map;  import android.os.Bundle; import android.app.Activity; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnFocusChangeListener; import android.view.ViewGroup; import android.view.Window; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.BaseAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.TextView;  public class MainActivity extends Activity implements View.OnClickListener {    private LinearLayout bottomLayout;// 底部菜单父框架   private LinearLayout bottomMenuLayout1;// 底部菜单布局   private LinearLayout bottomMenuLayout2;// 底部输入框布局   private RelativeLayout btn1;// “用户绑定”按钮布局   private RelativeLayout btn2;// “扫描签到”按钮布局   private RelativeLayout btn3;// “更多”按钮布局   private LinearLayout popLayout1;   private LinearLayout popLayout2;   private LinearLayout popLayout3;// 弹出的子菜单父框架布局   private LinearLayout childLayout;// “更多”按钮的子菜单   private ListView lv;   private MyAdapter adapter;   private List<Map<String, String>> listData = new ArrayList<Map<String, String>>();    private ImageView keyboard;// 底部键盘切换图标   private ImageView menu;// 底部菜单切换图标   private Button send;// 发送按钮   private EditText inputText;// 输入框    private boolean open = true;// 子菜单填充状态标记   private boolean flag = false;// 子菜单显示状态标记   private boolean bind = false;// 用户绑定状态标记    private Animation animEnter;// 底部菜单进入动画   private Animation animExit;// 底部菜单退出动画    private View view;   private View view2;   private LayoutInflater inflater;    private int myID = 0;    @Override   protected void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);     this.requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);     setContentView(R.layout.main);     getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,         R.layout.title_bar);// 自定义标题栏      inflater = MainActivity.this.getLayoutInflater();      popLayout1 = (LinearLayout) findViewById(R.id.pop_layout1);     popLayout2 = (LinearLayout) findViewById(R.id.pop_layout2);     popLayout3 = (LinearLayout) findViewById(R.id.pop_layout3);      bottomLayout = (LinearLayout) findViewById(R.id.bottom_layout);     bottomMenuLayout1 = (LinearLayout) findViewById(R.id.bottom_menu_layout1);      keyboard = (ImageView) findViewById(R.id.keyboard);     btn1 = (RelativeLayout) findViewById(R.id.btn1);     btn2 = (RelativeLayout) findViewById(R.id.btn2);     btn3 = (RelativeLayout) findViewById(R.id.btn3);      lv = (ListView) findViewById(R.id.lv);      btn1.setOnClickListener(this);     btn2.setOnClickListener(this);     btn3.setOnClickListener(this);     keyboard.setOnClickListener(this);      adapter = new MyAdapter(this, listData);     lv.setAdapter(adapter);    }    @Override   public void onClick(View v) {     // TODO Auto-generated method stub     int id = v.getId();     switch (id) {     case R.id.btn1:       btn1Click();       break;     case R.id.btn2:       break;     case R.id.btn3:       btn3Click();       break;     case R.id.keyboard:       keyboardClick();       break;     case R.id.menu:       menuClick();       break;     case R.id.add:       sendClick();       break;     default:       break;     }   }    public void btn1Click() {// 用户绑定     Map<String, String> map = new HashMap<String, String>();     map.put("type", "0");     if (!bind) {       map.put("text", "请输入您的手机号或简历ID进行帐号绑定,绑定成功后才能进行签到。");     } else {       map.put("text", "帐号已绑定成功,请您准时签到。");     }     listData.add(map);     adapter.notifyDataSetChanged();   }    public void btn2Click() {// 扫描签到     // TODO   }    public void btn3Click() {// 更多     if (open == true) {       view = inflater.inflate(R.layout.child_menu, popLayout3, true);       childLayout = (LinearLayout) view.findViewById(R.id.child_layout);       open = false;     }      if (flag == false) {       flag = true;       childLayout.setVisibility(View.VISIBLE);     } else {       flag = false;       childLayout.setVisibility(View.GONE);     }   }    public void keyboardClick() {//点击键盘按钮,由底部菜单切换为底部输入     view2 = inflater.inflate(R.layout.bottom_menu_layout2, bottomLayout,         true);     bottomMenuLayout2 = (LinearLayout) view2         .findViewById(R.id.bottom_menu_layout2);     animEnter = AnimationUtils.loadAnimation(MainActivity.this,         R.anim.my_pop_enter_anim);     animExit = AnimationUtils.loadAnimation(MainActivity.this,         R.anim.my_pop_exit_anim);     animEnter.setStartOffset(200);     bottomMenuLayout1.startAnimation(animExit);     bottomMenuLayout1.setVisibility(View.GONE);     bottomMenuLayout2.startAnimation(animEnter);     bottomMenuLayout2.setVisibility(View.VISIBLE);     menu = (ImageView) view2.findViewById(R.id.menu);     inputText = (EditText) view2.findViewById(R.id.input_text);     send = (Button) view2.findViewById(R.id.add);     menu.setOnClickListener(this);     send.setOnClickListener(this);     inputClick();   }    public void menuClick() {//点击菜单按钮,由底部输入框切换为底部菜单     bottomMenuLayout2.startAnimation(animExit);     bottomMenuLayout2.setVisibility(View.GONE);     bottomMenuLayout1.startAnimation(animEnter);     bottomMenuLayout1.setVisibility(View.VISIBLE);   }    public void inputClick() {     inputText.setOnFocusChangeListener(new OnFocusChangeListener() {        @Override       public void onFocusChange(View v, boolean hasFocus) {         // TODO Auto-generated method stub         if (hasFocus) {           send.setBackgroundResource(R.drawable.send_btn_bg);           send.setText("发送");         } else {           send.setBackgroundResource(R.drawable.add);           send.setText(" ");         }       }     });   }    public void sendClick() {     String text = inputText.getEditableText().toString();     inputText.setText("");     if (text != null && (!text.equals(""))) {       Map<String, String> map;       map = new HashMap<String, String>();       map.put("type", "1");// 消息类型,服务端为0,用户为1       map.put("text", text);       listData.add(map);        map = new HashMap<String, String>();       map.put("type", "0");       map.put("text", "帐号已绑定成功,请您准时签到。");       listData.add(map);       adapter.notifyDataSetChanged();       bind = true;     }   }    private class MyAdapter extends BaseAdapter {     public List<Map<String, String>> list;     private Context context;     private int type;     private ListView listView;      public MyAdapter(Context context, List<Map<String, String>> list) {       this.context = context;       this.list = list;     }      @Override     public int getCount() {       // TODO Auto-generated method stub       return list.size();     }      @Override     public Object getItem(int position) {       // TODO Auto-generated method stub       return list.get(position);     }      @Override     public long getItemId(int position) {       // TODO Auto-generated method stub       return position;     }      @Override     public View getView(int position, View convertView, ViewGroup parent) {       // TODO Auto-generated method stub       ViewHolder viewHolder = null;       Map<String, String> map = (Map<String, String>) list.get(position);       if (map.get("type").equals("0")) {// 服务端         if (convertView == null) {           convertView = inflater.inflate(R.layout.item_left, parent,               false);           viewHolder = new ViewHolder();           viewHolder.mTextView = (TextView) convertView               .findViewById(R.id.server_text);           viewHolder.mImageView = (ImageView) convertView               .findViewById(R.id.server_image);           convertView.setTag(viewHolder);         } else {           viewHolder = (ViewHolder) convertView.getTag();         }          viewHolder.mTextView.setText(map.get("text"));        } else {// 用户         if (convertView == null) {           convertView = inflater.inflate(R.layout.item_right, parent,               false);           viewHolder = new ViewHolder();           viewHolder.mTextView = (TextView) convertView               .findViewById(R.id.user_text);           viewHolder.mImageView = (ImageView) convertView               .findViewById(R.id.user_image);           convertView.setTag(viewHolder);         } else {           viewHolder = (ViewHolder) convertView.getTag();         }         viewHolder.mTextView.setText(map.get("text"));       }        return convertView;     }    }    private final class ViewHolder {     TextView mTextView;     ImageView mImageView;   }  } 

以上就是实现仿微信服务号的主要代码,菜单功能并没用完全实现,可根据实际情况和需要进行添加。同时还需注意的是,底部菜单最多为3个,每个名称限制在7个字符,包含的子菜单最多只能有5个。


注:相关教程知识阅读请移步到Android开发频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表