高仿手机QQ5.0界面框架

42 篇文章 0 订阅

这次的手机QQ更新从客观的角度来说,还是很好的,更加简约,控件也自定义了,界面也有了大的改动,但是最主要的框架还是它的左右滑动机制。让我们先来看看它的效果。

可以看到它是从左到右的一个滑动方法菜单的方式,最主要的就是这个控件类的实现吧。其他的感觉都没什么太大的问题,下面我就来看看这种效果应该怎么来实现。

第一拿到东西先分析这个效果是怎么出来的。我仔细的看了一下主要应该注意这几点。

1:菜单的出现有个放大效果而且伴随着一个apha的效果

2:主要的内容面板上面就是一个缩放的动画

3:可以看到这个菜单的边界和主内容面板上面的边界距离。我取的是1/4这里应该没错。

4:还应该注意的就是listview这些控件的事件屏蔽。

主要的问题应该就是这几个吧。

下面我就以怎么实现这个可滑动的pager来给大家说说代码实现。

package com.edsheng.view;

import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.Toast;

/**
 * @version 1.0
 * @FielName : DragPager.java
 * @Date : 2014/8/5
 * @author edsheng
 */
public class DragPager extends RelativeLayout {

	private View mMenu; // 菜单
	private View mContent; // 内容视图

	private int mStartx = 0; // 点击开始
	private float mContentStartTransX = 0; // 内容视图开始点击滑动的距离
	private float mMenuStartTransX = 0;// 菜单开始点击滑动的距离
	private int DEFAULT_RIGHT_MARGIN = getResources().getDisplayMetrics().widthPixels / 4;// 菜单距离边界距离在取的1/4屏幕

	ObjectAnimator mContent_animator;// 内容视图动画
	ObjectAnimator mMenu_animator;// 菜单动画
	private boolean misDrag = false; // 当前是否拖动
	final int DEFALT_DRAG_DISTENCE = 40;// 认为滑动的缺省值

	public DragPager(Context context) {
		super(context);
	}

	public DragPager(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	public DragPager(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public void setMenu(View menu) {
		mMenu = menu;
		LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT,
				LayoutParams.MATCH_PARENT);
		layoutParams.rightMargin = DEFAULT_RIGHT_MARGIN;
		addView(menu, layoutParams);
		mMenu.setScaleY(0.75f);// 初始化Y到0.75这么高
		mMenu.setTranslationX(-DEFAULT_RIGHT_MARGIN * 3);// 初始化菜单到-Y距离
	}

	public void setContent(View content) {
		mContent = content;
		addView(content);
	}

	/**
	 * 计算当前MenuX可滑动的位置
	 * 
	 * @param distence
	 * @return
	 */
	private float getMenuDragX(float distence) {
		float newX = distence + mMenuStartTransX;
		if (newX <= -DEFAULT_RIGHT_MARGIN * 3) {
			newX = -DEFAULT_RIGHT_MARGIN * 3;
		} else if (newX >= 0) {
			newX = 0;
		}
		return newX;
	}

	/**
	 * 计算内容视图X滑动的位置
	 * 
	 * @param distence
	 * @return
	 */
	private float getContentDragX(float distence) {

		float newX = distence + mContentStartTransX;
		if (newX <= 0) {
			newX = 0;
		} else if (newX >= mContent.getWidth() - DEFAULT_RIGHT_MARGIN) {
			newX = mContent.getWidth() - DEFAULT_RIGHT_MARGIN;
		}
		return newX;
	}

	/**
	 * 停止动画
	 */
	private void stopAnimation() {
		if (mContent_animator != null && mMenu_animator != null) {
			mContent_animator.cancel();
			mMenu_animator.cancel();
		}
	}

	// 移动
	private void move(float distence) {
		float nowx = getContentDragX(distence);
		if (nowx != mContent.getTranslationX()) {
			mContent.setTranslationX(nowx);
			float scale = nowx / (mContent.getWidth() - DEFAULT_RIGHT_MARGIN); // 计算alph范围是0-1
			mContent.setScaleY(1 - scale * 0.25f); // 内容的Y缩放
			mMenu.setTranslationX(getMenuDragX(distence)); // 设置菜单的距离
			mMenu.setScaleY(0.75f + scale * 0.25f);// 设置菜单的Y缩放
			mMenu.setAlpha(scale);// 菜单的Alpha
		}
	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			stopAnimation(); // 停止动画
			mStartx = (int) ev.getRawX(); // 获取点击初始化x
			if (mContent != null)
				mContentStartTransX = mContent.getTranslationX();// 获取初始化x
			if (mMenu != null)
				mMenuStartTransX = mMenu.getTranslationX();
			break;
		case MotionEvent.ACTION_MOVE:
			// 当左右滑动到阀值就认为是在拖动了
			if (Math.abs(ev.getRawX() - mStartx) > DEFALT_DRAG_DISTENCE) {
				misDrag = true;
			}
			break;
		case MotionEvent.ACTION_UP:
			misDrag = false;
			break;
		}
		return super.dispatchTouchEvent(ev);
	}

	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		if (misDrag) {
			return true;// 不进行向下分发了已经拦截
		} else {
			return false; // 把事件交给子view处理然后通过子view的dispatch分发
		}
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		if (event.getActionIndex() > 1)
			return true;
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			return true; // 消费掉这个事件让它不传递
		case MotionEvent.ACTION_MOVE:
			float distence = event.getRawX() - mStartx; // 在这里处理移动
			move(distence);
			break;
		case MotionEvent.ACTION_UP:
		case MotionEvent.ACTION_CANCEL:
			toggle(); // 窗口回弹
			break;
		}
		return super.onTouchEvent(event);
	}

	/**
	 * 回弹的动画
	 */
	private void toggle() {
		if (mContent.getTranslationX() > DEFAULT_RIGHT_MARGIN * 2) {
			// 向右动画
			// 先是content动画
			PropertyValuesHolder content_transani = PropertyValuesHolder
					.ofFloat("translationX", mContent.getTranslationX(),
							mContent.getWidth() - DEFAULT_RIGHT_MARGIN);
			PropertyValuesHolder content_ScaleY = PropertyValuesHolder.ofFloat(
					"scaleY", mContent.getScaleY(), 0.75f);
			mContent_animator = ObjectAnimator.ofPropertyValuesHolder(mContent,
					content_transani, content_ScaleY);
			mContent_animator.start();

			// 这里菜单动画

			PropertyValuesHolder menu_transani = PropertyValuesHolder.ofFloat(
					"translationX", mMenu.getTranslationX(), 0);
			PropertyValuesHolder menu_ScaleY = PropertyValuesHolder.ofFloat(
					"scaleY", mMenu.getScaleY(), 1f);
			PropertyValuesHolder menu_Alpha = PropertyValuesHolder.ofFloat(
					"Alpha", mMenu.getAlpha(), 1f);
			mMenu_animator = ObjectAnimator.ofPropertyValuesHolder(mMenu,
					menu_transani, menu_ScaleY, menu_Alpha);
			mMenu_animator.start();

		} else {
			// 向左动画
			PropertyValuesHolder content_transanx = PropertyValuesHolder
					.ofFloat("translationX", mContent.getTranslationX(), 0);
			PropertyValuesHolder content_ScaleY = PropertyValuesHolder.ofFloat(
					"scaleY", mContent.getScaleY(), 1.0f);
			mContent_animator = ObjectAnimator.ofPropertyValuesHolder(mContent,
					content_transanx, content_ScaleY);
			mContent_animator.start();

			PropertyValuesHolder menu_transani = PropertyValuesHolder.ofFloat(
					"translationX", mMenu.getTranslationX(),
					-DEFAULT_RIGHT_MARGIN * 3);
			PropertyValuesHolder menu_ScaleY = PropertyValuesHolder.ofFloat(
					"scaleY", mMenu.getScaleY(), 0.75f);
			PropertyValuesHolder menu_Alpha = PropertyValuesHolder.ofFloat(
					"Alpha", mMenu.getAlpha(), 0f);
			mMenu_animator = ObjectAnimator.ofPropertyValuesHolder(mMenu,
					menu_transani, menu_ScaleY, menu_Alpha);
			mMenu_animator.start();
		}

	}

}


其中需要注意的地方就是事件的屏蔽和拖动的处理,然后就是几个缩放的地方,然后我们来验证一下这个控件是可用,它的左边是一个menu右边是一个content当我们需要使用的时候应该这样来使用。

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		DragPager dragPager = new DragPager(this);
		View content = new View(this);
		content.setBackgroundColor(Color.BLUE);
		dragPager.setContent(content);
		View mentu = new View(this);
		mentu.setBackgroundColor(Color.RED);
		dragPager.setBackgroundColor(Color.argb(122, 122, 122, 122));
		dragPager.setMenu(mentu);
		setContentView(dragPager);
}


 

最后还是来看看它的效果怎么样吧。

这里卡的原因主要是因为我的GIF做的不好的原因,然后只要这个界面出来了,其他的东西都比较好搞了,本来想彻彻底底的把手机QQ5.0的界面搬过来的,但是无耐手Q的加密现在做的越来越好了,拿不到资源了,不过这个界面都出来,我相信其他界面还是很容易搞定的吧,这个是里面我感觉最主要的一个东西。有兴趣的童鞋可以继续往下写哦,也可以把这个当成一个控件来用哦。


 

 

高仿QQ聊天 登录界面 import java.awt.BorderLayout; import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.JTextPane; import javax.swing.UIManager; import javax.swing.text.BadLocationException; import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyleConstants; import javax.swing.text.StyledDocument; public class Test extends JFrame { private JScrollPane scrollPane = null; // 滚动 private JTextPane text = null; private Box box = null; // 放输入组件的容器 private JButton b_insert = null, b_remove = null, b_icon = null; // 插入按钮;清除按钮;插入图片按钮 private JTextField addText = null; // 文字输入框 // 字体名称;字号大小;文字样式;文字颜色;文字背景颜色 private JComboBox fontName = null, fontSize = null, fontStyle = null, fontColor = null, fontBackColor = null; private StyledDocument doc = null; // 非常重要插入文字样式就靠它了 public Test() { super("JTextPane Test"); try { // 使用Windows的界面风格 UIManager.setLookAndFeel ("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); } catch (Exception e) { e.printStackTrace(); } text = new JTextPane(); text.setEditable(false); // 不可录入 doc = text.getStyledDocument(); // 获得JTextPane的Document scrollPane = new JScrollPane(text); addText = new JTextField(18); String[] str_name = { "宋体", "黑体", "Dialog", "Gulim" }; String[] str_Size = { "12", "14", "18", "22", "30", "40" }; String[] str_Style = { "常规", "斜体", "粗体", "粗斜体" }; String[] str_Color = { "黑色", "红色", "蓝色", "黄色", "绿色" }; String[] str_BackColor = { "无色", "灰色", "淡红", "淡蓝", "淡黄", "淡绿" }; fontName = new JComboBox(str_name); // 字体名称 fontSize = new JComboBox(str_Size); // 字号 fontStyle = new JComboBox(str_Style); // 样式 fontColor = new JComboBox(str_Color); // 颜色 fontBackColor = new JComboBox(str_BackColor); // 背景颜色 b_insert = new JButton("插入"); // 插入 b_remove = new JButton("清空"); // 清除 b_icon = new JButton("图片"); // 插入图片 b_insert.addActionListener(new ActionListener() { // 插入文字的事件 public void actionPerformed(ActionEvent e) { insert(getFontAttrib()); addText.setText(""); } }); b_remove.addActionListener(new ActionListener() { // 清除事件 public void actionPerformed(ActionEvent e) { text.setText(""); } }); b_icon.addActionListener(new ActionListener() { // 插入图片事件 public void actionPerformed(ActionEvent arg0) { JFileChooser f = new JFileChooser(); // 查找文件 f.showOpenDialog(null); insertIcon(f.getSelectedFile()); // 插入图片 } }); box = Box.createVerticalBox(); // 竖结构 Box box_1 = Box.createHorizontalBox(); // 横结构 Box box_2 = Box.createHorizontalBox(); // 横结构 box.add(box_1); box.add(Box.createVerticalStrut(8)); // 两行的间距 box.add(box_2); box.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8)); // 8个的边距 // 开始将所需组件加入容器 box_1.add(new JLabel("字体:")); // 加入标签 box_1.add(fontName); // 加入组件 box_1.add(Box.createHorizontalStrut(8)); // 间距 box_1.add(new JLabel("样式:")); box_1.add(fontStyle); box_1.add(Box.createHorizontalStrut(8)); box_1.add(new JLabel("字号:")); box_1.add(fontSize); box_1.add(Box.createHorizontalStrut(8)); box_1.add(new JLabel("颜色:")); box_1.add(fontColor); box_1.add(Box.createHorizontalStrut(8)); box_1.add(new JLabel("背景:")); box_1.add(fontBackColor); box_1.add(Box.createHorizontalStrut(8)); box_1.add(b_icon); box_2.add(addText); box_2.add(Box.createHorizontalStrut(8)); box_2.add(b_insert); box_2.add(Box.createHorizontalStrut(8)); box_2.add(b_remove); this.getRootPane().setDefaultButton(b_insert); // 默认回车按钮 this.getContentPane().add(scrollPane); this.getContentPane().add(box, BorderLayout.SOUTH); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setSize(600, 400); this.setLocationRelativeTo(null); this.setVisible(true); addText.requestFocus(); } /** * 插入图片 * * @param icon */ private void insertIcon(File file) { text.setCaretPosition(doc.getLength()); // 设置插入位置 text.insertIcon(new ImageIcon(file.getPath())); // 插入图片 insert(new FontAttrib()); // 这样做可以换行 } /** * 将文本插入JTextPane * * @param attrib */ private void insert(FontAttrib attrib) { try { // 插入文本 doc.insertString(doc.getLength(), attrib.getText() + "\n", attrib.getAttrSet()); } catch (BadLocationException e) { e.printStackTrace(); } } /** * 获取所需要的文字设置 * * @return FontAttrib */ private FontAttrib getFontAttrib() { FontAttrib att = new FontAttrib(); att.setText(addText.getText()); att.setName((String) fontName.getSelectedItem()); att.setSize(Integer.parseInt((String) fontSize.getSelectedItem())); String temp_style = (String) fontStyle.getSelectedItem(); if (temp_style.equals("常规")) { att.setStyle(FontAttrib.GENERAL); } else if (temp_style.equals("粗体")) { att.setStyle(FontAttrib.BOLD); } else if (temp_style.equals("斜体")) { att.setStyle(FontAttrib.ITALIC); } else if (temp_style.equals("粗斜体")) { att.setStyle(FontAttrib.BOLD_ITALIC); } String temp_color = (String) fontColor.getSelectedItem(); if (temp_color.equals("黑色")) { att.setColor(new Color(0, 0, 0)); } else if (temp_color.equals("红色")) { att.setColor(new Color(255, 0, 0)); } else if (temp_color.equals("蓝色")) { att.setColor(new Color(0, 0, 255)); } else if (temp_color.equals("黄色")) { att.setColor(new Color(255, 255, 0)); } else if (temp_color.equals("绿色")) { att.setColor(new Color(0, 255, 0)); } String temp_backColor = (String) fontBackColor.getSelectedItem(); if (!temp_backColor.equals("无色")) { if (temp_backColor.equals("灰色")) { att.setBackColor(new Color(200, 200, 200)); } else if (temp_backColor.equals("淡红")) { att.setBackColor(new Color(255, 200, 200)); } else if (temp_backColor.equals("淡蓝")) { att.setBackColor(new Color(200, 200, 255)); } else if (temp_backColor.equals("淡黄")) { att.setBackColor(new Color(255, 255, 200)); } else if (temp_backColor.equals("淡绿")) { att.setBackColor(new Color(200, 255, 200)); } } return att; } public static void main(String args[]) { new Test(); } /** * 字体的属性类 */ private class FontAttrib { public static final int GENERAL = 0; // 常规 public static final int BOLD = 1; // 粗体 public static final int ITALIC = 2; // 斜体 public static final int BOLD_ITALIC = 3; // 粗斜体 private SimpleAttributeSet attrSet = null; // 属性集 private String text = null, name = null; // 要输入的文本和字体名称 private int style = 0, size = 0; // 样式和字号 private Color color = null, backColor = null; // 文字颜色和背景颜色 /** * 一个空的构造(可当做换行使用) */ public FontAttrib() { } /** * 返回属性集 * * @return */ public SimpleAttributeSet getAttrSet() { attrSet = new SimpleAttributeSet(); if (name != null) StyleConstants.setFontFamily(attrSet, name); if (style == FontAttrib.GENERAL) { StyleConstants.setBold(attrSet, false); StyleConstants.setItalic(attrSet, false); } else if (style == FontAttrib.BOLD) { StyleConstants.setBold(attrSet, true); StyleConstants.setItalic(attrSet, false); } else if (style == FontAttrib.ITALIC) { StyleConstants.setBold(attrSet, false); StyleConstants.setItalic(attrSet, true); } else if (style == FontAttrib.BOLD_ITALIC) { StyleConstants.setBold(attrSet, true); StyleConstants.setItalic(attrSet, true); } StyleConstants.setFontSize(attrSet, size); if (color != null) StyleConstants.setForeground(attrSet, color); if (backColor != null) StyleConstants.setBackground(attrSet, backColor); return attrSet; } /** * 设置属性集 * * @param attrSet */ public void setAttrSet(SimpleAttributeSet attrSet) { this.attrSet = attrSet; } /* 后面的注释就不了,一看就明白 */ public String getText() { return text; } public void setText(String text) { this.text = text; } public Color getColor() { return color; } public void setColor(Color color) { this.color = color; } public Color getBackColor() { return backColor; } public void setBackColor(Color backColor) { this.backColor = backColor; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getSize() { return size; } public void setSize(int size) { this.size = size; } public int getStyle() { return style; } public void setStyle(int style) { this.style = style; } } }
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值